Compare commits

...

5 Commits

76 changed files with 7459 additions and 160 deletions

View File

@@ -45,10 +45,9 @@ SubTitle: JavaScript Mapping Library
# --------------------------------------------------------------------------
File: OpenLayers (OpenLayers.js)
Group: OpenLayers {
File: OpenLayers (no auto-title, OpenLayers.js)
File: Ajax (no auto-title, OpenLayers/Ajax.js)
Group: BaseTypes {
@@ -76,6 +75,7 @@ Group: OpenLayers {
File: EditingToolbar (no auto-title, OpenLayers/Control/EditingToolbar.js)
File: KeyboardDefaults (no auto-title, OpenLayers/Control/KeyboardDefaults.js)
File: LayerSwitcher (no auto-title, OpenLayers/Control/LayerSwitcher.js)
File: Measure (no auto-title, OpenLayers/Control/Measure.js)
File: ModifyFeature (no auto-title, OpenLayers/Control/ModifyFeature.js)
File: MouseDefaults (no auto-title, OpenLayers/Control/MouseDefaults.js)
File: MousePosition (no auto-title, OpenLayers/Control/MousePosition.js)
@@ -84,7 +84,9 @@ Group: OpenLayers {
File: NavigationHistory (no auto-title, OpenLayers/Control/NavigationHistory.js)
File: NavToolbar (no auto-title, OpenLayers/Control/NavToolbar.js)
File: OverviewMap (no auto-title, OpenLayers/Control/OverviewMap.js)
File: Pan (no auto-title, OpenLayers/Control/Pan.js)
File: Panel (no auto-title, OpenLayers/Control/Panel.js)
File: PanPanel (no auto-title, OpenLayers/Control/PanPanel.js)
File: PanZoom (no auto-title, OpenLayers/Control/PanZoom.js)
File: PanZoomBar (no auto-title, OpenLayers/Control/PanZoomBar.js)
File: Permalink (no auto-title, OpenLayers/Control/Permalink.js)
@@ -92,6 +94,9 @@ Group: OpenLayers {
File: ScaleLine (no auto-title, OpenLayers/Control/ScaleLine.js)
File: SelectFeature (no auto-title, OpenLayers/Control/SelectFeature.js)
File: ZoomBox (no auto-title, OpenLayers/Control/ZoomBox.js)
File: ZoomIn (no auto-title, OpenLayers/Control/ZoomIn.js)
File: ZoomOut (no auto-title, OpenLayers/Control/ZoomOut.js)
File: ZoomPanel (no auto-title, OpenLayers/Control/ZoomPanel.js)
File: ZoomToMaxExtent (no auto-title, OpenLayers/Control/ZoomToMaxExtent.js)
} # Group: Control
@@ -110,17 +115,39 @@ Group: OpenLayers {
File: Comparison (no auto-title, OpenLayers/Filter/Comparison.js)
File: FeatureId (no auto-title, OpenLayers/Filter/FeatureId.js)
File: Logical (no auto-title, OpenLayers/Filter/Logical.js)
File: Spatial (no auto-title, OpenLayers/Filter/Spatial.js)
} # Group: Filter
Group: Format {
File: Format (no auto-title, OpenLayers/Format.js)
Group: Filter {
File: Filter (no auto-title, OpenLayers/Format/Filter.js)
File: v1 (no auto-title, OpenLayers/Format/Filter/v1.js)
File: v1_0_0 (no auto-title, OpenLayers/Format/Filter/v1_0_0.js)
} # Group: Filter
File: GeoJSON (no auto-title, OpenLayers/Format/GeoJSON.js)
File: GeoRSS (no auto-title, OpenLayers/Format/GeoRSS.js)
File: GML (no auto-title, OpenLayers/Format/GML.js)
Group: GML {
File: GML (no auto-title, OpenLayers/Format/GML.js)
File: Base (no auto-title, OpenLayers/Format/GML/Base.js)
File: v2 (no auto-title, OpenLayers/Format/GML/v2.js)
File: v3 (no auto-title, OpenLayers/Format/GML/v3.js)
} # Group: GML
File: GPX (no auto-title, OpenLayers/Format/GPX.js)
File: JSON (no auto-title, OpenLayers/Format/JSON.js)
File: KML (no auto-title, OpenLayers/Format/KML.js)
File: OSM (no auto-title, OpenLayers/Format/OSM.js)
File: Text (no auto-title, OpenLayers/Format/Text.js)
File: WFS (no auto-title, OpenLayers/Format/WFS.js)
File: WKT (no auto-title, OpenLayers/Format/WKT.js)
File: XML (no auto-title, OpenLayers/Format/XML.js)
Group: SLD {
@@ -129,11 +156,6 @@ Group: OpenLayers {
File: v1_0_0 (no auto-title, OpenLayers/Format/SLD/v1_0_0.js)
} # Group: SLD
File: Text (no auto-title, OpenLayers/Format/Text.js)
File: WFS (no auto-title, OpenLayers/Format/WFS.js)
File: WKT (no auto-title, OpenLayers/Format/WKT.js)
File: XML (no auto-title, OpenLayers/Format/XML.js)
Group: WMC {
File: WMC (no auto-title, OpenLayers/Format/WMC.js)
@@ -180,11 +202,18 @@ Group: OpenLayers {
Group: Lang {
File: Lang (no auto-title, OpenLayers/Lang.js)
File: Lang["cs-CZ"] (OpenLayers/Lang/cs-CZ.js)
File: Lang["de"] (no auto-title, OpenLayers/Lang/de.js)
File: Lang["en"] (no auto-title, OpenLayers/Lang/en.js)
File: Lang["en-CA"] (no auto-title, OpenLayers/Lang/en-CA.js)
File: Lang["fr"] (no auto-title, OpenLayers/Lang/fr.js)
File: cs-CZ (no auto-title, OpenLayers/Lang/cs-CZ.js)
File: de (no auto-title, OpenLayers/Lang/de.js)
File: en (no auto-title, OpenLayers/Lang/en.js)
File: en-CA (no auto-title, OpenLayers/Lang/en-CA.js)
File: fr (no auto-title, OpenLayers/Lang/fr.js)
File: it (no auto-title, OpenLayers/Lang/it.js)
File: nb (no auto-title, OpenLayers/Lang/nb.js)
File: nl (no auto-title, OpenLayers/Lang/nl.js)
File: pt-BR (no auto-title, OpenLayers/Lang/pt-BR.js)
File: sv-SE (no auto-title, OpenLayers/Lang/sv-SE.js)
File: zh-CN (no auto-title, OpenLayers/Lang/zh-CN.js)
File: zh-TW (no auto-title, OpenLayers/Lang/zh-TW.js)
} # Group: Lang
Group: Layer {
@@ -200,6 +229,7 @@ Group: OpenLayers {
File: HTTPRequest (no auto-title, OpenLayers/Layer/HTTPRequest.js)
File: Image (no auto-title, OpenLayers/Layer/Image.js)
File: KaMap (no auto-title, OpenLayers/Layer/KaMap.js)
File: KaMapCache (no auto-title, OpenLayers/Layer/KaMapCache.js)
File: MapGuide (no auto-title, OpenLayers/Layer/MapGuide.js)
File: MapServer (no auto-title, OpenLayers/Layer/MapServer.js)
File: MapServer.Untiled (no auto-title, OpenLayers/Layer/MapServer/Untiled.js)
@@ -232,21 +262,51 @@ Group: OpenLayers {
File: Popup (no auto-title, OpenLayers/Popup.js)
File: Anchored (no auto-title, OpenLayers/Popup/Anchored.js)
File: AnchoredBubble (no auto-title, OpenLayers/Popup/AnchoredBubble.js)
File: Framed (OpenLayers/Popup/Framed.js)
File: FramedCloud (OpenLayers/Popup/FramedCloud.js)
File: Framed (no auto-title, OpenLayers/Popup/Framed.js)
File: FramedCloud (no auto-title, OpenLayers/Popup/FramedCloud.js)
} # Group: Popup
File: Projection (no auto-title, OpenLayers/Projection.js)
Group: Protocol {
File: Protocol (no auto-title, OpenLayers/Protocol.js)
File: HTTP (no auto-title, OpenLayers/Protocol/HTTP.js)
Group: SQL {
File: SQL (no auto-title, OpenLayers/Protocol/SQL.js)
File: Gears (no auto-title, OpenLayers/Protocol/SQL/Gears.js)
} # Group: SQL
} # Group: Protocol
Group: Renderer {
File: Renderer (no auto-title, OpenLayers/Renderer.js)
File: Canvas (no auto-title, OpenLayers/Renderer/Canvas.js)
File: Elements (no auto-title, OpenLayers/Renderer/Elements.js)
File: SVG (no auto-title, OpenLayers/Renderer/SVG.js)
File: VML (no auto-title, OpenLayers/Renderer/VML.js)
} # Group: Renderer
Group: Request {
File: Request (no auto-title, OpenLayers/Request.js)
File: XMLHttpRequest (no auto-title, OpenLayers/Request/XMLHttpRequest.js)
} # Group: Request
File: Rule (no auto-title, OpenLayers/Rule.js)
Group: Strategy {
File: Strategy (no auto-title, OpenLayers/Strategy.js)
File: BBOX (no auto-title, OpenLayers/Strategy/BBOX.js)
File: Cluster (no auto-title, OpenLayers/Strategy/Cluster.js)
File: Fixed (no auto-title, OpenLayers/Strategy/Fixed.js)
File: Paging (no auto-title, OpenLayers/Strategy/Paging.js)
} # Group: Strategy
File: Style (no auto-title, OpenLayers/Style.js)
File: StyleMap (no auto-title, OpenLayers/StyleMap.js)

View File

@@ -52,3 +52,41 @@
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*/
/**
* Contains portions of Gears <http://code.google.com/apis/gears/>
*
* Copyright 2007, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of Google Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Sets up google.gears.*, which is *the only* supported way to access Gears.
*
* Circumvent this file at your own risk!
*
* In the future, Gears may automatically define google.gears.* without this
* file. Gears may use these objects to transparently fix bugs and compatibility
* issues. Applications that use the code below will continue to work seamlessly
* when that happens.
*/

View File

@@ -45,10 +45,9 @@ SubTitle: JavaScript Mapping Library
# --------------------------------------------------------------------------
File: OpenLayers (OpenLayers.js)
Group: OpenLayers {
File: OpenLayers (no auto-title, OpenLayers.js)
File: Ajax (no auto-title, OpenLayers/Ajax.js)
Group: BaseTypes {
@@ -76,6 +75,7 @@ Group: OpenLayers {
File: EditingToolbar (no auto-title, OpenLayers/Control/EditingToolbar.js)
File: KeyboardDefaults (no auto-title, OpenLayers/Control/KeyboardDefaults.js)
File: LayerSwitcher (no auto-title, OpenLayers/Control/LayerSwitcher.js)
File: Measure (no auto-title, OpenLayers/Control/Measure.js)
File: ModifyFeature (no auto-title, OpenLayers/Control/ModifyFeature.js)
File: MouseDefaults (no auto-title, OpenLayers/Control/MouseDefaults.js)
File: MousePosition (no auto-title, OpenLayers/Control/MousePosition.js)
@@ -84,7 +84,9 @@ Group: OpenLayers {
File: NavigationHistory (no auto-title, OpenLayers/Control/NavigationHistory.js)
File: NavToolbar (no auto-title, OpenLayers/Control/NavToolbar.js)
File: OverviewMap (no auto-title, OpenLayers/Control/OverviewMap.js)
File: Pan (no auto-title, OpenLayers/Control/Pan.js)
File: Panel (no auto-title, OpenLayers/Control/Panel.js)
File: PanPanel (no auto-title, OpenLayers/Control/PanPanel.js)
File: PanZoom (no auto-title, OpenLayers/Control/PanZoom.js)
File: PanZoomBar (no auto-title, OpenLayers/Control/PanZoomBar.js)
File: Permalink (no auto-title, OpenLayers/Control/Permalink.js)
@@ -92,6 +94,9 @@ Group: OpenLayers {
File: ScaleLine (no auto-title, OpenLayers/Control/ScaleLine.js)
File: SelectFeature (no auto-title, OpenLayers/Control/SelectFeature.js)
File: ZoomBox (no auto-title, OpenLayers/Control/ZoomBox.js)
File: ZoomIn (no auto-title, OpenLayers/Control/ZoomIn.js)
File: ZoomOut (no auto-title, OpenLayers/Control/ZoomOut.js)
File: ZoomPanel (no auto-title, OpenLayers/Control/ZoomPanel.js)
File: ZoomToMaxExtent (no auto-title, OpenLayers/Control/ZoomToMaxExtent.js)
} # Group: Control
@@ -110,17 +115,39 @@ Group: OpenLayers {
File: Comparison (no auto-title, OpenLayers/Filter/Comparison.js)
File: FeatureId (no auto-title, OpenLayers/Filter/FeatureId.js)
File: Logical (no auto-title, OpenLayers/Filter/Logical.js)
File: Spatial (no auto-title, OpenLayers/Filter/Spatial.js)
} # Group: Filter
Group: Format {
File: Format (no auto-title, OpenLayers/Format.js)
Group: Filter {
File: Filter (no auto-title, OpenLayers/Format/Filter.js)
File: v1 (no auto-title, OpenLayers/Format/Filter/v1.js)
File: v1_0_0 (no auto-title, OpenLayers/Format/Filter/v1_0_0.js)
} # Group: Filter
File: GeoJSON (no auto-title, OpenLayers/Format/GeoJSON.js)
File: GeoRSS (no auto-title, OpenLayers/Format/GeoRSS.js)
File: GML (no auto-title, OpenLayers/Format/GML.js)
Group: GML {
File: GML (no auto-title, OpenLayers/Format/GML.js)
File: Base (no auto-title, OpenLayers/Format/GML/Base.js)
File: v2 (no auto-title, OpenLayers/Format/GML/v2.js)
File: v3 (no auto-title, OpenLayers/Format/GML/v3.js)
} # Group: GML
File: GPX (no auto-title, OpenLayers/Format/GPX.js)
File: JSON (no auto-title, OpenLayers/Format/JSON.js)
File: KML (no auto-title, OpenLayers/Format/KML.js)
File: OSM (no auto-title, OpenLayers/Format/OSM.js)
File: Text (no auto-title, OpenLayers/Format/Text.js)
File: WFS (no auto-title, OpenLayers/Format/WFS.js)
File: WKT (no auto-title, OpenLayers/Format/WKT.js)
File: XML (no auto-title, OpenLayers/Format/XML.js)
Group: SLD {
@@ -129,11 +156,6 @@ Group: OpenLayers {
File: v1_0_0 (no auto-title, OpenLayers/Format/SLD/v1_0_0.js)
} # Group: SLD
File: Text (no auto-title, OpenLayers/Format/Text.js)
File: WFS (no auto-title, OpenLayers/Format/WFS.js)
File: WKT (no auto-title, OpenLayers/Format/WKT.js)
File: XML (no auto-title, OpenLayers/Format/XML.js)
Group: WMC {
File: WMC (no auto-title, OpenLayers/Format/WMC.js)
@@ -180,11 +202,18 @@ Group: OpenLayers {
Group: Lang {
File: Lang (no auto-title, OpenLayers/Lang.js)
File: Lang["cs-CZ"] (OpenLayers/Lang/cs-CZ.js)
File: Lang["de"] (no auto-title, OpenLayers/Lang/de.js)
File: Lang["en"] (no auto-title, OpenLayers/Lang/en.js)
File: Lang["en-CA"] (no auto-title, OpenLayers/Lang/en-CA.js)
File: Lang["fr"] (no auto-title, OpenLayers/Lang/fr.js)
File: cs-CZ (no auto-title, OpenLayers/Lang/cs-CZ.js)
File: de (no auto-title, OpenLayers/Lang/de.js)
File: en (no auto-title, OpenLayers/Lang/en.js)
File: en-CA (no auto-title, OpenLayers/Lang/en-CA.js)
File: fr (no auto-title, OpenLayers/Lang/fr.js)
File: it (no auto-title, OpenLayers/Lang/it.js)
File: nb (no auto-title, OpenLayers/Lang/nb.js)
File: nl (no auto-title, OpenLayers/Lang/nl.js)
File: pt-BR (no auto-title, OpenLayers/Lang/pt-BR.js)
File: sv-SE (no auto-title, OpenLayers/Lang/sv-SE.js)
File: zh-CN (no auto-title, OpenLayers/Lang/zh-CN.js)
File: zh-TW (no auto-title, OpenLayers/Lang/zh-TW.js)
} # Group: Lang
Group: Layer {
@@ -200,6 +229,7 @@ Group: OpenLayers {
File: HTTPRequest (no auto-title, OpenLayers/Layer/HTTPRequest.js)
File: Image (no auto-title, OpenLayers/Layer/Image.js)
File: KaMap (no auto-title, OpenLayers/Layer/KaMap.js)
File: KaMapCache (no auto-title, OpenLayers/Layer/KaMapCache.js)
File: MapGuide (no auto-title, OpenLayers/Layer/MapGuide.js)
File: MapServer (no auto-title, OpenLayers/Layer/MapServer.js)
File: MapServer.Untiled (no auto-title, OpenLayers/Layer/MapServer/Untiled.js)
@@ -232,21 +262,51 @@ Group: OpenLayers {
File: Popup (no auto-title, OpenLayers/Popup.js)
File: Anchored (no auto-title, OpenLayers/Popup/Anchored.js)
File: AnchoredBubble (no auto-title, OpenLayers/Popup/AnchoredBubble.js)
File: Framed (OpenLayers/Popup/Framed.js)
File: FramedCloud (OpenLayers/Popup/FramedCloud.js)
File: Framed (no auto-title, OpenLayers/Popup/Framed.js)
File: FramedCloud (no auto-title, OpenLayers/Popup/FramedCloud.js)
} # Group: Popup
File: Projection (no auto-title, OpenLayers/Projection.js)
Group: Protocol {
File: Protocol (no auto-title, OpenLayers/Protocol.js)
File: HTTP (no auto-title, OpenLayers/Protocol/HTTP.js)
Group: SQL {
File: SQL (no auto-title, OpenLayers/Protocol/SQL.js)
File: Gears (no auto-title, OpenLayers/Protocol/SQL/Gears.js)
} # Group: SQL
} # Group: Protocol
Group: Renderer {
File: Renderer (no auto-title, OpenLayers/Renderer.js)
File: Canvas (no auto-title, OpenLayers/Renderer/Canvas.js)
File: Elements (no auto-title, OpenLayers/Renderer/Elements.js)
File: SVG (no auto-title, OpenLayers/Renderer/SVG.js)
File: VML (no auto-title, OpenLayers/Renderer/VML.js)
} # Group: Renderer
Group: Request {
File: Request (no auto-title, OpenLayers/Request.js)
File: XMLHttpRequest (no auto-title, OpenLayers/Request/XMLHttpRequest.js)
} # Group: Request
File: Rule (no auto-title, OpenLayers/Rule.js)
Group: Strategy {
File: Strategy (no auto-title, OpenLayers/Strategy.js)
File: BBOX (no auto-title, OpenLayers/Strategy/BBOX.js)
File: Cluster (no auto-title, OpenLayers/Strategy/Cluster.js)
File: Fixed (no auto-title, OpenLayers/Strategy/Fixed.js)
File: Paging (no auto-title, OpenLayers/Strategy/Paging.js)
} # Group: Strategy
File: Style (no auto-title, OpenLayers/Style.js)
File: StyleMap (no auto-title, OpenLayers/StyleMap.js)

670
examples/animator.js Normal file
View File

@@ -0,0 +1,670 @@
/*
Animator.js 1.1.9
This library is released under the BSD license:
Copyright (c) 2006, Bernard Sumption. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer. Redistributions in binary
form must reproduce the above copyright notice, this list of conditions and
the following disclaimer in the documentation and/or other materials
provided with the distribution. Neither the name BernieCode nor
the names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/
// Applies a sequence of numbers between 0 and 1 to a number of subjects
// construct - see setOptions for parameters
function Animator(options) {
this.setOptions(options);
var _this = this;
this.timerDelegate = function(){_this.onTimerEvent()};
this.subjects = [];
this.target = 0;
this.state = 0;
this.lastTime = null;
};
Animator.prototype = {
// apply defaults
setOptions: function(options) {
this.options = Animator.applyDefaults({
interval: 20, // time between animation frames
duration: 400, // length of animation
onComplete: function(){},
onStep: function(){},
transition: Animator.tx.easeInOut
}, options);
},
// animate from the current state to provided value
seekTo: function(to) {
this.seekFromTo(this.state, to);
},
// animate from the current state to provided value
seekFromTo: function(from, to) {
this.target = Math.max(0, Math.min(1, to));
this.state = Math.max(0, Math.min(1, from));
this.lastTime = new Date().getTime();
if (!this.intervalId) {
this.intervalId = window.setInterval(this.timerDelegate, this.options.interval);
}
},
// animate from the current state to provided value
jumpTo: function(to) {
this.target = this.state = Math.max(0, Math.min(1, to));
this.propagate();
},
// seek to the opposite of the current target
toggle: function() {
this.seekTo(1 - this.target);
},
// add a function or an object with a method setState(state) that will be called with a number
// between 0 and 1 on each frame of the animation
addSubject: function(subject) {
this.subjects[this.subjects.length] = subject;
return this;
},
// remove all subjects
clearSubjects: function() {
this.subjects = [];
},
// forward the current state to the animation subjects
propagate: function() {
var value = this.options.transition(this.state);
for (var i=0; i<this.subjects.length; i++) {
if (this.subjects[i].setState) {
this.subjects[i].setState(value);
} else {
this.subjects[i](value);
}
}
},
// called once per frame to update the current state
onTimerEvent: function() {
var now = new Date().getTime();
var timePassed = now - this.lastTime;
this.lastTime = now;
var movement = (timePassed / this.options.duration) * (this.state < this.target ? 1 : -1);
if (Math.abs(movement) >= Math.abs(this.state - this.target)) {
this.state = this.target;
} else {
this.state += movement;
}
try {
this.propagate();
} finally {
this.options.onStep.call(this);
if (this.target == this.state) {
window.clearInterval(this.intervalId);
this.intervalId = null;
this.options.onComplete.call(this);
}
}
},
// shortcuts
play: function() {this.seekFromTo(0, 1)},
reverse: function() {this.seekFromTo(1, 0)},
// return a string describing this Animator, for debugging
inspect: function() {
var str = "#<Animator:\n";
for (var i=0; i<this.subjects.length; i++) {
str += this.subjects[i].inspect();
}
str += ">";
return str;
}
}
// merge the properties of two objects
Animator.applyDefaults = function(defaults, prefs) {
prefs = prefs || {};
var prop, result = {};
for (prop in defaults) result[prop] = prefs[prop] !== undefined ? prefs[prop] : defaults[prop];
return result;
}
// make an array from any object
Animator.makeArray = function(o) {
if (o == null) return [];
if (!o.length) return [o];
var result = [];
for (var i=0; i<o.length; i++) result[i] = o[i];
return result;
}
// convert a dash-delimited-property to a camelCaseProperty (c/o Prototype, thanks Sam!)
Animator.camelize = function(string) {
var oStringList = string.split('-');
if (oStringList.length == 1) return oStringList[0];
var camelizedString = string.indexOf('-') == 0
? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
: oStringList[0];
for (var i = 1, len = oStringList.length; i < len; i++) {
var s = oStringList[i];
camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
}
return camelizedString;
}
// syntactic sugar for creating CSSStyleSubjects
Animator.apply = function(el, style, options) {
if (style instanceof Array) {
return new Animator(options).addSubject(new CSSStyleSubject(el, style[0], style[1]));
}
return new Animator(options).addSubject(new CSSStyleSubject(el, style));
}
// make a transition function that gradually accelerates. pass a=1 for smooth
// gravitational acceleration, higher values for an exaggerated effect
Animator.makeEaseIn = function(a) {
return function(state) {
return Math.pow(state, a*2);
}
}
// as makeEaseIn but for deceleration
Animator.makeEaseOut = function(a) {
return function(state) {
return 1 - Math.pow(1 - state, a*2);
}
}
// make a transition function that, like an object with momentum being attracted to a point,
// goes past the target then returns
Animator.makeElastic = function(bounces) {
return function(state) {
state = Animator.tx.easeInOut(state);
return ((1-Math.cos(state * Math.PI * bounces)) * (1 - state)) + state;
}
}
// make an Attack Decay Sustain Release envelope that starts and finishes on the same level
//
Animator.makeADSR = function(attackEnd, decayEnd, sustainEnd, sustainLevel) {
if (sustainLevel == null) sustainLevel = 0.5;
return function(state) {
if (state < attackEnd) {
return state / attackEnd;
}
if (state < decayEnd) {
return 1 - ((state - attackEnd) / (decayEnd - attackEnd) * (1 - sustainLevel));
}
if (state < sustainEnd) {
return sustainLevel;
}
return sustainLevel * (1 - ((state - sustainEnd) / (1 - sustainEnd)));
}
}
// make a transition function that, like a ball falling to floor, reaches the target and/
// bounces back again
Animator.makeBounce = function(bounces) {
var fn = Animator.makeElastic(bounces);
return function(state) {
state = fn(state);
return state <= 1 ? state : 2-state;
}
}
// pre-made transition functions to use with the 'transition' option
Animator.tx = {
easeInOut: function(pos){
return ((-Math.cos(pos*Math.PI)/2) + 0.5);
},
linear: function(x) {
return x;
},
easeIn: Animator.makeEaseIn(1.5),
easeOut: Animator.makeEaseOut(1.5),
strongEaseIn: Animator.makeEaseIn(2.5),
strongEaseOut: Animator.makeEaseOut(2.5),
elastic: Animator.makeElastic(1),
veryElastic: Animator.makeElastic(3),
bouncy: Animator.makeBounce(1),
veryBouncy: Animator.makeBounce(3)
}
// animates a pixel-based style property between two integer values
function NumericalStyleSubject(els, property, from, to, units) {
this.els = Animator.makeArray(els);
if (property == 'opacity' && window.ActiveXObject) {
this.property = 'filter';
} else {
this.property = Animator.camelize(property);
}
this.from = parseFloat(from);
this.to = parseFloat(to);
this.units = units != null ? units : 'px';
}
NumericalStyleSubject.prototype = {
setState: function(state) {
var style = this.getStyle(state);
var visibility = (this.property == 'opacity' && state == 0) ? 'hidden' : '';
var j=0;
for (var i=0; i<this.els.length; i++) {
try {
this.els[i].style[this.property] = style;
} catch (e) {
// ignore fontWeight - intermediate numerical values cause exeptions in firefox
if (this.property != 'fontWeight') throw e;
}
if (j++ > 20) return;
}
},
getStyle: function(state) {
state = this.from + ((this.to - this.from) * state);
if (this.property == 'filter') return "alpha(opacity=" + Math.round(state*100) + ")";
if (this.property == 'opacity') return state;
return Math.round(state) + this.units;
},
inspect: function() {
return "\t" + this.property + "(" + this.from + this.units + " to " + this.to + this.units + ")\n";
}
}
// animates a colour based style property between two hex values
function ColorStyleSubject(els, property, from, to) {
this.els = Animator.makeArray(els);
this.property = Animator.camelize(property);
this.to = this.expandColor(to);
this.from = this.expandColor(from);
this.origFrom = from;
this.origTo = to;
}
ColorStyleSubject.prototype = {
// parse "#FFFF00" to [256, 256, 0]
expandColor: function(color) {
var hexColor, red, green, blue;
hexColor = ColorStyleSubject.parseColor(color);
if (hexColor) {
red = parseInt(hexColor.slice(1, 3), 16);
green = parseInt(hexColor.slice(3, 5), 16);
blue = parseInt(hexColor.slice(5, 7), 16);
return [red,green,blue]
}
if (window.DEBUG) {
alert("Invalid colour: '" + color + "'");
}
},
getValueForState: function(color, state) {
return Math.round(this.from[color] + ((this.to[color] - this.from[color]) * state));
},
setState: function(state) {
var color = '#'
+ ColorStyleSubject.toColorPart(this.getValueForState(0, state))
+ ColorStyleSubject.toColorPart(this.getValueForState(1, state))
+ ColorStyleSubject.toColorPart(this.getValueForState(2, state));
for (var i=0; i<this.els.length; i++) {
this.els[i].style[this.property] = color;
}
},
inspect: function() {
return "\t" + this.property + "(" + this.origFrom + " to " + this.origTo + ")\n";
}
}
// return a properly formatted 6-digit hex colour spec, or false
ColorStyleSubject.parseColor = function(string) {
var color = '#', match;
if(match = ColorStyleSubject.parseColor.rgbRe.exec(string)) {
var part;
for (var i=1; i<=3; i++) {
part = Math.max(0, Math.min(255, parseInt(match[i])));
color += ColorStyleSubject.toColorPart(part);
}
return color;
}
if (match = ColorStyleSubject.parseColor.hexRe.exec(string)) {
if(match[1].length == 3) {
for (var i=0; i<3; i++) {
color += match[1].charAt(i) + match[1].charAt(i);
}
return color;
}
return '#' + match[1];
}
return false;
}
// convert a number to a 2 digit hex string
ColorStyleSubject.toColorPart = function(number) {
if (number > 255) number = 255;
var digits = number.toString(16);
if (number < 16) return '0' + digits;
return digits;
}
ColorStyleSubject.parseColor.rgbRe = /^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i;
ColorStyleSubject.parseColor.hexRe = /^\#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
// Animates discrete styles, i.e. ones that do not scale but have discrete values
// that can't be interpolated
function DiscreteStyleSubject(els, property, from, to, threshold) {
this.els = Animator.makeArray(els);
this.property = Animator.camelize(property);
this.from = from;
this.to = to;
this.threshold = threshold || 0.5;
}
DiscreteStyleSubject.prototype = {
setState: function(state) {
var j=0;
for (var i=0; i<this.els.length; i++) {
this.els[i].style[this.property] = state <= this.threshold ? this.from : this.to;
}
},
inspect: function() {
return "\t" + this.property + "(" + this.from + " to " + this.to + " @ " + this.threshold + ")\n";
}
}
// animates between two styles defined using CSS.
// if style1 and style2 are present, animate between them, if only style1
// is present, animate between the element's current style and style1
function CSSStyleSubject(els, style1, style2) {
els = Animator.makeArray(els);
this.subjects = [];
if (els.length == 0) return;
var prop, toStyle, fromStyle;
if (style2) {
fromStyle = this.parseStyle(style1, els[0]);
toStyle = this.parseStyle(style2, els[0]);
} else {
toStyle = this.parseStyle(style1, els[0]);
fromStyle = {};
for (prop in toStyle) {
fromStyle[prop] = CSSStyleSubject.getStyle(els[0], prop);
}
}
// remove unchanging properties
var prop;
for (prop in fromStyle) {
if (fromStyle[prop] == toStyle[prop]) {
delete fromStyle[prop];
delete toStyle[prop];
}
}
// discover the type (numerical or colour) of each style
var prop, units, match, type, from, to;
for (prop in fromStyle) {
var fromProp = String(fromStyle[prop]);
var toProp = String(toStyle[prop]);
if (toStyle[prop] == null) {
if (window.DEBUG) alert("No to style provided for '" + prop + '"');
continue;
}
if (from = ColorStyleSubject.parseColor(fromProp)) {
to = ColorStyleSubject.parseColor(toProp);
type = ColorStyleSubject;
} else if (fromProp.match(CSSStyleSubject.numericalRe)
&& toProp.match(CSSStyleSubject.numericalRe)) {
from = parseFloat(fromProp);
to = parseFloat(toProp);
type = NumericalStyleSubject;
match = CSSStyleSubject.numericalRe.exec(fromProp);
var reResult = CSSStyleSubject.numericalRe.exec(toProp);
if (match[1] != null) {
units = match[1];
} else if (reResult[1] != null) {
units = reResult[1];
} else {
units = reResult;
}
} else if (fromProp.match(CSSStyleSubject.discreteRe)
&& toProp.match(CSSStyleSubject.discreteRe)) {
from = fromProp;
to = toProp;
type = DiscreteStyleSubject;
units = 0; // hack - how to get an animator option down to here
} else {
if (window.DEBUG) {
alert("Unrecognised format for value of "
+ prop + ": '" + fromStyle[prop] + "'");
}
continue;
}
this.subjects[this.subjects.length] = new type(els, prop, from, to, units);
}
}
CSSStyleSubject.prototype = {
// parses "width: 400px; color: #FFBB2E" to {width: "400px", color: "#FFBB2E"}
parseStyle: function(style, el) {
var rtn = {};
// if style is a rule set
if (style.indexOf(":") != -1) {
var styles = style.split(";");
for (var i=0; i<styles.length; i++) {
var parts = CSSStyleSubject.ruleRe.exec(styles[i]);
if (parts) {
rtn[parts[1]] = parts[2];
}
}
}
// else assume style is a class name
else {
var prop, value, oldClass;
oldClass = el.className;
el.className = style;
for (var i=0; i<CSSStyleSubject.cssProperties.length; i++) {
prop = CSSStyleSubject.cssProperties[i];
value = CSSStyleSubject.getStyle(el, prop);
if (value != null) {
rtn[prop] = value;
}
}
el.className = oldClass;
}
return rtn;
},
setState: function(state) {
for (var i=0; i<this.subjects.length; i++) {
this.subjects[i].setState(state);
}
},
inspect: function() {
var str = "";
for (var i=0; i<this.subjects.length; i++) {
str += this.subjects[i].inspect();
}
return str;
}
}
// get the current value of a css property,
CSSStyleSubject.getStyle = function(el, property){
var style;
if(document.defaultView && document.defaultView.getComputedStyle){
style = document.defaultView.getComputedStyle(el, "").getPropertyValue(property);
if (style) {
return style;
}
}
property = Animator.camelize(property);
if(el.currentStyle){
style = el.currentStyle[property];
}
return style || el.style[property]
}
CSSStyleSubject.ruleRe = /^\s*([a-zA-Z\-]+)\s*:\s*(\S(.+\S)?)\s*$/;
CSSStyleSubject.numericalRe = /^-?\d+(?:\.\d+)?(%|[a-zA-Z]{2})?$/;
CSSStyleSubject.discreteRe = /^\w+$/;
// required because the style object of elements isn't enumerable in Safari
/*
CSSStyleSubject.cssProperties = ['background-color','border','border-color','border-spacing',
'border-style','border-top','border-right','border-bottom','border-left','border-top-color',
'border-right-color','border-bottom-color','border-left-color','border-top-width','border-right-width',
'border-bottom-width','border-left-width','border-width','bottom','color','font-size','font-size-adjust',
'font-stretch','font-style','height','left','letter-spacing','line-height','margin','margin-top',
'margin-right','margin-bottom','margin-left','marker-offset','max-height','max-width','min-height',
'min-width','orphans','outline','outline-color','outline-style','outline-width','overflow','padding',
'padding-top','padding-right','padding-bottom','padding-left','quotes','right','size','text-indent',
'top','width','word-spacing','z-index','opacity','outline-offset'];*/
CSSStyleSubject.cssProperties = ['azimuth','background','background-attachment','background-color','background-image','background-position','background-repeat','border-collapse','border-color','border-spacing','border-style','border-top','border-top-color','border-right-color','border-bottom-color','border-left-color','border-top-style','border-right-style','border-bottom-style','border-left-style','border-top-width','border-right-width','border-bottom-width','border-left-width','border-width','bottom','clear','clip','color','content','cursor','direction','display','elevation','empty-cells','css-float','font','font-family','font-size','font-size-adjust','font-stretch','font-style','font-variant','font-weight','height','left','letter-spacing','line-height','list-style','list-style-image','list-style-position','list-style-type','margin','margin-top','margin-right','margin-bottom','margin-left','max-height','max-width','min-height','min-width','orphans','outline','outline-color','outline-style','outline-width','overflow','padding','padding-top','padding-right','padding-bottom','padding-left','pause','position','right','size','table-layout','text-align','text-decoration','text-indent','text-shadow','text-transform','top','vertical-align','visibility','white-space','width','word-spacing','z-index','opacity','outline-offset','overflow-x','overflow-y'];
// chains several Animator objects together
function AnimatorChain(animators, options) {
this.animators = animators;
this.setOptions(options);
for (var i=0; i<this.animators.length; i++) {
this.listenTo(this.animators[i]);
}
this.forwards = false;
this.current = 0;
}
AnimatorChain.prototype = {
// apply defaults
setOptions: function(options) {
this.options = Animator.applyDefaults({
// by default, each call to AnimatorChain.play() calls jumpTo(0) of each animator
// before playing, which can cause flickering if you have multiple animators all
// targeting the same element. Set this to false to avoid this.
resetOnPlay: true
}, options);
},
// play each animator in turn
play: function() {
this.forwards = true;
this.current = -1;
if (this.options.resetOnPlay) {
for (var i=0; i<this.animators.length; i++) {
this.animators[i].jumpTo(0);
}
}
this.advance();
},
// play all animators backwards
reverse: function() {
this.forwards = false;
this.current = this.animators.length;
if (this.options.resetOnPlay) {
for (var i=0; i<this.animators.length; i++) {
this.animators[i].jumpTo(1);
}
}
this.advance();
},
// if we have just play()'d, then call reverse(), and vice versa
toggle: function() {
if (this.forwards) {
this.seekTo(0);
} else {
this.seekTo(1);
}
},
// internal: install an event listener on an animator's onComplete option
// to trigger the next animator
listenTo: function(animator) {
var oldOnComplete = animator.options.onComplete;
var _this = this;
animator.options.onComplete = function() {
if (oldOnComplete) oldOnComplete.call(animator);
_this.advance();
}
},
// play the next animator
advance: function() {
if (this.forwards) {
if (this.animators[this.current + 1] == null) return;
this.current++;
this.animators[this.current].play();
} else {
if (this.animators[this.current - 1] == null) return;
this.current--;
this.animators[this.current].reverse();
}
},
// this function is provided for drop-in compatibility with Animator objects,
// but only accepts 0 and 1 as target values
seekTo: function(target) {
if (target <= 0) {
this.forwards = false;
this.animators[this.current].seekTo(0);
} else {
this.forwards = true;
this.animators[this.current].seekTo(1);
}
}
}
// an Accordion is a class that creates and controls a number of Animators. An array of elements is passed in,
// and for each element an Animator and a activator button is created. When an Animator's activator button is
// clicked, the Animator and all before it seek to 0, and all Animators after it seek to 1. This can be used to
// create the classic Accordion effect, hence the name.
// see setOptions for arguments
function Accordion(options) {
this.setOptions(options);
var selected = this.options.initialSection, current;
if (this.options.rememberance) {
current = document.location.hash.substring(1);
}
this.rememberanceTexts = [];
this.ans = [];
var _this = this;
for (var i=0; i<this.options.sections.length; i++) {
var el = this.options.sections[i];
var an = new Animator(this.options.animatorOptions);
var from = this.options.from + (this.options.shift * i);
var to = this.options.to + (this.options.shift * i);
an.addSubject(new NumericalStyleSubject(el, this.options.property, from, to, this.options.units));
an.jumpTo(0);
var activator = this.options.getActivator(el);
activator.index = i;
activator.onclick = function(){_this.show(this.index)};
this.ans[this.ans.length] = an;
this.rememberanceTexts[i] = activator.innerHTML.replace(/\s/g, "");
if (this.rememberanceTexts[i] === current) {
selected = i;
}
}
this.show(selected);
}
Accordion.prototype = {
// apply defaults
setOptions: function(options) {
this.options = Object.extend({
// REQUIRED: an array of elements to use as the accordion sections
sections: null,
// a function that locates an activator button element given a section element.
// by default it takes a button id from the section's "activator" attibute
getActivator: function(el) {return document.getElementById(el.getAttribute("activator"))},
// shifts each animator's range, for example with options {from:0,to:100,shift:20}
// the animators' ranges will be 0-100, 20-120, 40-140 etc.
shift: 0,
// the first page to show
initialSection: 0,
// if set to true, document.location.hash will be used to preserve the open section across page reloads
rememberance: true,
// constructor arguments to the Animator objects
animatorOptions: {}
}, options || {});
},
show: function(section) {
for (var i=0; i<this.ans.length; i++) {
this.ans[i].seekTo(i > section ? 1 : 0);
}
if (this.options.rememberance) {
document.location.hash = this.rememberanceTexts[section];
}
}
}

View File

@@ -92,6 +92,31 @@
document.getElementById('noneToggle').checked = true;
}
function calcVincenty(geometry) {
/**
* Note: this function assumes geographic coordinates and
* will fail otherwise. OpenLayers.Util.distVincenty takes
* two objects representing points with geographic coordinates
* and returns the geodesic distance between them (shortest
* distance between the two points on an ellipsoid) in *kilometers*.
*
* It is important to realize that the segments drawn on the map
* are *not* geodesics (or "great circle" segments). This means
* that in general, the measure returned by this function
* will not represent the length of segments drawn on the map.
*/
var dist = 0;
for (var i = 1; i < geometry.components.length; i++) {
var first = geometry.components[i-1];
var second = geometry.components[i];
dist += OpenLayers.Util.distVincenty(
{lon: first.x, lat: first.y},
{lon: second.x, lat: second.y}
);
}
return dist;
}
function handleMeasurements(event) {
var geometry = event.geometry;
@@ -102,6 +127,10 @@
var out = "";
if(order == 1) {
out += "measure: " + measure.toFixed(3) + " " + units;
if (map.getProjection() == "EPSG:4326") {
out += "<br /> Great Circle Distance: " +
calcVincenty(geometry).toFixed(3) + " km *";
}
} else {
out += "measure: " + measure.toFixed(3) + " " + units + "<sup>2</" + "sup>";
}
@@ -144,6 +173,12 @@
<label for="polygonToggle">measure area</label>
</li>
</ul>
<p>* Note that the geometries drawn are planar geometries and the
metrics returned by the measure control are planar measures. The
"great circle" distance does not necessarily represent the length
of the segments drawn on the map. Instead, it is a geodesic metric that
represents the cumulative shortest path between all vertices in the
geometry were they projected onto a sphere.</p>
</div>
</body>
</html>

View File

@@ -0,0 +1,261 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" href="../theme/default/style.css" type="text/css" />
<link rel="stylesheet" href="style.css" type="text/css" />
<style type="text/css">
.float-left {
float: left;
}
.clear-left {
clear: left;
}
</style>
<script src="../lib/OpenLayers.js"></script>
<script type="text/javascript">
var map, vector, protocol, modify;
function init() {
// create Gears protocol
protocol = new OpenLayers.Protocol.SQL.Gears({
databaseName: "db_name",
tableName: "table_name",
saveFeatureState: false
});
if (!GearsIsSupported()) {
return;
}
map = new OpenLayers.Map("map");
// create base layer
var layer = new OpenLayers.Layer.WMS("OpenLayers WMS",
"http://labs.metacarta.com/wms/vmap0",
{"layers": "basic"}
);
map.addLayer(layer);
// create vector layer
vector = new OpenLayers.Layer.Vector("Vector", {
protocol: protocol,
strategies : [new OpenLayers.Strategy.Fixed()],
eventListeners: {
featuremodified: function(obj) {
if (obj.feature.state != OpenLayers.State.INSERT &&
obj.feature.state != OpenLayers.State.DELETE) {
obj.feature.state = OpenLayers.State.UPDATE;
}
displayStatus();
}
}
});
map.addLayer(vector);
// create modify feature control
modify = new OpenLayers.Control.ModifyFeature(vector);
// create editing panel
var panel = new OpenLayers.Control.Panel({
displayClass: "olControlEditingToolbar"
});
var navigation = new OpenLayers.Control.Navigation({
eventListeners: {
activate: function(obj) {
modify.activate();
},
deactivate: function(obj) {
modify.deactivate();
}
}
});
var editing = new OpenLayers.Control.DrawFeature(
vector, OpenLayers.Handler.Polygon, {
displayClass: "olControlDrawFeaturePolygon",
eventListeners: {
featureadded: function(obj) {
obj.feature.state = OpenLayers.State.INSERT;
displayStatus();
}
}
});
panel.addControls([navigation, editing]);
panel.defaultControl = navigation;
// add controls to the map
map.addControl(modify);
map.addControl(panel);
// center the map
map.setCenter(new OpenLayers.LonLat(5, 40), 5);
}
function displayResult(txt) {
if (window.resultDomElement === undefined) {
window.resultDomElement = OpenLayers.Util.getElement("last-result");
}
resultDomElement.innerHTML = txt;
displayStatus();
}
function displayStatus() {
if (window.statusDomElement === undefined) {
window.statusDomElement = OpenLayers.Util.getElement("status");
}
var createCnt = 0;
var updateCnt = 0;
var deleteCnt = 0;
var i, len, state;
for (i = 0, len = vector.features.length; i < len; i++) {
state = vector.features[i].state;
if (state == OpenLayers.State.INSERT) {
createCnt++;
} else if (state == OpenLayers.State.UPDATE) {
updateCnt++;
} else if (state == OpenLayers.State.DELETE) {
deleteCnt++;
}
}
statusDomElement.innerHTML = createCnt + " features to create, " +
updateCnt + " features to update, " +
deleteCnt + " features to delete";
}
function GearsIsSupported() {
if (!protocol.supported()) {
OpenLayers.Console.userError("You must install Gears prior to using this example");
return false;
}
return true;
}
function featuresWithState(state) {
var list = [];
var i, len, feature;
for (i = 0, len = vector.features.length; i < len; i++) {
feature = vector.features[i];
if (feature.state == state) {
list.push(feature);
}
}
return list;
}
function _sync() {
if (!GearsIsSupported()) {
return;
}
var resp = protocol.read();
if (!resp.success()) {
OpenLayers.Console.error("reading from Gears DB failed");
return;
}
vector.destroyFeatures();
if (!resp.features || resp.features.length <= 0) {
displayResult("No features to read");
return;
}
vector.addFeatures(resp.features);
displayResult("features successfully read");
}
function _commit() {
if (!GearsIsSupported()) {
return;
}
var error = false;
function callback(resp) {
if (error) {
return;
}
if (!resp.success()) {
OpenLayers.Console.error("Commiting to Gears DB failed");
error = true;
return;
}
modify.selectControl.unselectAll()
if (resp.reqFeatures) {
vector.destroyFeatures(resp.reqFeatures);
}
if (resp.features) {
vector.addFeatures(resp.features);
}
}
if (vector.features.length > 0) {
protocol.commit(vector.features, {
"create": {
callback: callback
},
"update": {
callback: callback
},
"delete": {
callback: callback
}
});
if (!error) {
displayResult("features successfully committed");
}
} else {
displayResult("no features to commit");
}
}
function _delete() {
if (!GearsIsSupported()) {
return;
}
var feature = vector.selectedFeatures[0];
if (feature) {
modify.selectControl.unselectAll()
feature.state = OpenLayers.State.DELETE;
displayStatus();
}
}
</script>
</head>
<body onload="init()">
<h1 id="title">Gears Protocol Example</h1>
<div id="tags">
</div>
<p id="shortdesc">
Shows the usage of the Gears protocol.
</p>
<div class="float-left">
<div id="map" class="smallmap"></div>
</div>
<div>
<a href="javascript:_sync()">Sync</a>
<p>The Sync link destroys the features currently in the layer, reads
features from the Gears database, and adds them to the layer.
Uncommitted features will be lost.</p>
<a href="javascript:_commit()">Commit</a>
<p>The Commit link commits to the Gears database the features that are
marked as INSERT, UPDATE or DELETE.</p>
<a href="javascript:_delete()">Delete</a>
<p>The Delete link marks the selected feature as DELETE. To select a feature
click choose the navigation control in the editing toolbar.</p>
</div>
<div style="margin-top: 30px">
<p>Status: <span id="status"></span></p>
<p>Result: <span id="last-result"></span></p>
</div>
<div class="clear-left" id="docs">
<p>This example demonstrates the usage of OpenLayers Gears protocol to
read/create/update/delete features from/to the Gears database.
<a href="http://gears.google.com/">Gears</a> must obviously be installed
in your browser for this example to work.</p>
</div>
</body>
</html>

View File

@@ -18,7 +18,7 @@ import sys, os
allowedHosts = ['www.openlayers.org', 'openlayers.org',
'labs.metacarta.com', 'world.freemap.in',
'prototype.openmnnd.org', 'geo.openplans.org',
'sigma.openplans.org'
'sigma.openplans.org',
'www.openstreetmap.org']
method = os.environ["REQUEST_METHOD"]
@@ -40,8 +40,8 @@ try:
print "Status: 502 Bad Gateway"
print "Content-Type: text/plain"
print
print "This proxy does not allow you to access that location."
print
print "This proxy does not allow you to access that location (%s)." % (host,)
print
print os.environ
elif url.startswith("http://") or url.startswith("https://"):

View File

@@ -28,6 +28,7 @@
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326"),
units: "m",
numZoomLevels: 18,
maxResolution: 156543.0339,
maxExtent: new OpenLayers.Bounds(-20037508, -20037508,
20037508, 20037508.34)
@@ -86,8 +87,8 @@
attribution: '<a href="http://www.openstreetmap.org/">OpenStreetMap</a>'
}
);
// create OSM layer
var mapnik = new OpenLayers.Layer.TMS(
// create OAM layer
var oam = new OpenLayers.Layer.TMS(
"OpenAerialMap",
"http://tile.openaerialmap.org/tiles/1.0.0/openaerialmap-900913/",
{
@@ -95,10 +96,20 @@
}
);
// create OSM layer
var mapnik = new OpenLayers.Layer.TMS(
"OpenStreetMap (Mapnik)",
"http://a.tile.openstreetmap.org/",
{
type: 'png', getURL: osm_getTileURL,
displayOutsideMaxExtent: true,
attribution: '<a href="http://www.openstreetmap.org/">OpenStreetMap</a>'
}
);
// create OSM layer
var osmarender = new OpenLayers.Layer.TMS(
"OpenStreetMap (Tiles@Home)",
"http://tah.openstreetmap.org/Tiles/tile.php/",
"http://tah.openstreetmap.org/Tiles/tile/",
{
type: 'png', getURL: osm_getTileURL,
displayOutsideMaxExtent: true,
@@ -122,7 +133,7 @@
var vector = new OpenLayers.Layer.Vector("Editable Vectors");
map.addLayers([gmap, gsat, ghyb, veroad, veaer, vehyb,
yahoo, yahoosat, yahoohyb, mapnik, osmarender,
yahoo, yahoosat, yahoohyb, oam, mapnik, osmarender,
wms, vector]);
map.addControl(new OpenLayers.Control.LayerSwitcher());
map.addControl(new OpenLayers.Control.EditingToolbar(vector));

View File

@@ -0,0 +1,64 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>OpenLayers BBOX Strategy Example</title>
<link rel="stylesheet" href="../theme/default/style.css" type="text/css" />
<link rel="stylesheet" href="style.css" type="text/css" />
<script src="../lib/OpenLayers.js"></script>
<script type="text/javascript">
var map, photos;
OpenLayers.ProxyHost = (window.location.host == "localhost") ?
"/cgi-bin/proxy.cgi?url=" : "proxy.cgi?url=";
function init() {
map = new OpenLayers.Map('map', {
restrictedExtent: new OpenLayers.Bounds(-180, -90, 180, 90)
});
var base = new OpenLayers.Layer.WMS("OpenLayers WMS",
["http://t3.labs.metacarta.com/wms-c/Basic.py",
"http://t2.labs.metacarta.com/wms-c/Basic.py",
"http://t1.labs.metacarta.com/wms-c/Basic.py"],
{layers: 'satellite'}
);
var style = new OpenLayers.Style({
externalGraphic: "${img_url}",
pointRadius: 30
});
photos = new OpenLayers.Layer.Vector("Photos", {
strategies: [new OpenLayers.Strategy.BBOX()],
protocol: new OpenLayers.Protocol.HTTP({
url: "http://labs.metacarta.com/flickrbrowse/flickr.py/flickr",
params: {
format: "WFS",
sort: "interestingness-desc",
service: "WFS",
request: "GetFeatures",
srs: "EPSG:4326",
maxfeatures: 10
},
format: new OpenLayers.Format.GML()
}),
styleMap: new OpenLayers.StyleMap(style)
});
map.addLayers([base, photos]);
map.setCenter(new OpenLayers.LonLat(-116.45, 35.42), 5);
}
</script>
</head>
<body onload="init()">
<h1 id="title">BBOX Strategy Example</h1>
<p id="shortdesc">
Uses a BBOX strategy to request features within a bounding box.
</p>
<div id="map" class="smallmap"></div>
<div id="docs">
<p>The BBOX strategy requests data within a bounding box. When the
previously requested data bounds are invalidated (by browsing to
some area not covered by those bounds), another request for data
is issued.</p>
</div>
</body>
</html>

View File

@@ -0,0 +1,201 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>OpenLayers Cluster Strategy Example</title>
<link rel="stylesheet" href="../theme/default/style.css" type="text/css" />
<link rel="stylesheet" href="style.css" type="text/css" />
<style type="text/css">
#photos {
height: 100px;
width: 512px;
position: relative;
white-space: nowrap;
}
.shift {
height: 25px;
line-height: 25px;
background-color: #fefefe;
text-align: center;
position: absolute;
bottom: 10px;
font-size: 8px;
font-weight: bold;
color: #696969;
width: 25px;
}
#scroll-start {
left: 0px;
}
#scroll-end {
right: 0px;
}
#scroll {
left: 30px;
width: 452px;
height: 100px;
overflow: hidden;
position: absolute;
bottom: 0px;
}
#photos ul {
position: absolute;
bottom: 0px;
padding: 0;
margin: 0;
}
#photos ul.start {
left: 0px;
}
#photos ul.end {
right: 80px;
}
#photos ul li {
padding 10px;
margin: 0;
list-style: none;
display: inline;
}
img.thumb {
height: 30px;
}
img.big {
height: 90px;
}
</style>
<script src="../lib/OpenLayers.js"></script>
<script src="Jugl.js"></script>
<script src="animator.js"></script>
<script type="text/javascript">
var map, template;
var Jugl = window["http://jugl.tschaub.net/trunk/lib/Jugl.js"];
OpenLayers.ProxyHost = (window.location.host == "localhost") ?
"/cgi-bin/proxy.cgi?url=" : "proxy.cgi?url=";
function init() {
map = new OpenLayers.Map('map', {
restrictedExtent: new OpenLayers.Bounds(-180, -90, 180, 90)
});
var base = new OpenLayers.Layer.WMS("OpenLayers WMS",
["http://t3.labs.metacarta.com/wms-c/Basic.py",
"http://t2.labs.metacarta.com/wms-c/Basic.py",
"http://t1.labs.metacarta.com/wms-c/Basic.py"],
{layers: 'satellite'}
);
var style = new OpenLayers.Style({
pointRadius: "${radius}",
fillColor: "#ffcc66",
fillOpacity: 0.8,
strokeColor: "#cc6633",
strokeWidth: 2,
strokeOpacity: 0.8
}, {
context: {
radius: function(feature) {
return Math.min(feature.attributes.count, 7) + 3;
}
}
});
var photos = new OpenLayers.Layer.Vector("Photos", {
strategies: [
new OpenLayers.Strategy.Fixed(),
new OpenLayers.Strategy.Cluster()
],
protocol: new OpenLayers.Protocol.HTTP({
url: "http://labs.metacarta.com/flickrbrowse/flickr.py/flickr",
params: {
format: "WFS",
sort: "interestingness-desc",
service: "WFS",
request: "GetFeatures",
srs: "EPSG:4326",
maxfeatures: 150,
bbox: [-180, -90, 180, 90]
},
format: new OpenLayers.Format.GML()
}),
styleMap: new OpenLayers.StyleMap({
"default": style,
"select": {
fillColor: "#8aeeef",
strokeColor: "#32a8a9"
}
})
});
var select = new OpenLayers.Control.SelectFeature(
photos, {hover: true}
);
map.addControl(select);
select.activate();
photos.events.on({"featureselected": display});
map.addLayers([base, photos]);
map.setCenter(new OpenLayers.LonLat(0, 0), 1);
// template setup
template = new Jugl.Template("template");
}
function display(event) {
// clear previous photo list and create new one
$("photos").innerHTML = "";
var node = template.process({
context: {features: event.feature.cluster},
clone: true,
parent: $("photos")
});
// set up forward/rewind
var forward = Animator.apply($("list"), ["start", "end"], {duration: 1500});
$("scroll-end").onmouseover = function() {forward.seekTo(1)};
$("scroll-end").onmouseout = function() {forward.seekTo(forward.state)};
$("scroll-start").onmouseover = function() {forward.seekTo(0)};
$("scroll-start").onmouseout = function() {forward.seekTo(forward.state)};
// set up photo zoom
for(var i=0; i<event.feature.cluster.length; ++i) {
listen($("link-" + i), Animator.apply($("photo-" + i), ["thumb", "big"]));
}
}
function listen(el, anim) {
el.onmouseover = function() {anim.seekTo(1)};
el.onmouseout = function() {anim.seekTo(0)};
}
</script>
</head>
<body onload="init()">
<h1 id="title">Cluster Strategy Example</h1>
<p id="shortdesc">
Uses a cluster strategy to render points representing clusters of features.
</p>
<div id="map" class="smallmap"></div>
<div id="docs">
<p>The Cluster strategy lets you display points representing clusters
of features within some pixel distance.</p>
</div>
<div id="photos"></div>
<p>Hover over a cluster on the map to see the photos it includes.</p>
<div style="display: none;">
<div id="template">
<div class="shift" id="scroll-start">&lt;&lt;</div>
<div id="scroll">
<ul id="list" class="start">
<li jugl:repeat="feature features">
<a jugl:attributes="href feature.attributes.img_url;
id 'link-' + repeat.feature.index"
target="_blank">
<img jugl:attributes="src feature.attributes.img_url;
title feature.attributes.title;
id 'photo-' + repeat.feature.index"
class="thumb" />
</a>
</li>
</ul>
</div>
<div class="shift" id="scroll-end">&gt;&gt;</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,78 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>OpenLayers Paging Strategy Example</title>
<link rel="stylesheet" href="../theme/default/style.css" type="text/css" />
<link rel="stylesheet" href="style.css" type="text/css" />
<script src="../lib/OpenLayers.js"></script>
<script type="text/javascript">
var map, photos, paging;
OpenLayers.ProxyHost = (window.location.host == "localhost") ?
"/cgi-bin/proxy.cgi?url=" : "proxy.cgi?url=";
function init() {
map = new OpenLayers.Map('map', {
restrictedExtent: new OpenLayers.Bounds(-180, -90, 180, 90)
});
var base = new OpenLayers.Layer.WMS("OpenLayers WMS",
["http://t3.labs.metacarta.com/wms-c/Basic.py",
"http://t2.labs.metacarta.com/wms-c/Basic.py",
"http://t1.labs.metacarta.com/wms-c/Basic.py"],
{layers: 'satellite'}
);
var style = new OpenLayers.Style({
externalGraphic: "${img_url}",
pointRadius: 30
});
paging = new OpenLayers.Strategy.Paging();
photos = new OpenLayers.Layer.Vector("Photos", {
strategies: [new OpenLayers.Strategy.Fixed(), paging],
protocol: new OpenLayers.Protocol.HTTP({
url: "http://labs.metacarta.com/flickrbrowse/flickr.py/flickr",
params: {
format: "WFS",
sort: "interestingness-desc",
service: "WFS",
request: "GetFeatures",
srs: "EPSG:4326",
maxfeatures: 100,
bbox: [-180, -90, 180, 90]
},
format: new OpenLayers.Format.GML()
}),
styleMap: new OpenLayers.StyleMap(style)
});
map.addLayers([base, photos]);
photos.events.on({"featuresadded": updateButtons});
map.setCenter(new OpenLayers.LonLat(0, 0), 1);
}
function updateButtons() {
document.getElementById("prev").disabled = (paging.pageNum() < 1);
document.getElementById("next").disabled = (paging.pageNum() >= paging.pageCount() - 1);
document.getElementById("num").innerHTML = paging.pageNum() + 1;
document.getElementById("count").innerHTML = paging.pageCount();
}
</script>
</head>
<body onload="init()">
<h1 id="title">Paging Strategy Example</h1>
<p id="shortdesc">
Uses a paging strategy to cache large batches of features and render a page at a time.
</p>
<div id="map" class="smallmap"></div>
Displaying page <span id="num">0</span> of <span id="count">...</span>
<button id="prev" disabled="disabled" onclick="paging.pagePrevious();">previous</button>
<button id="next" disabled="disabled" onclick="paging.pageNext();">next</button>
<br /><br />
<div id="docs">
<p>The Paging strategy lets you apply client side paging for protocols
that do not support paging on the server. In this case, the protocol requests a
batch of 100 features, the strategy caches those and supplies a single
page at a time to the layer.</p>
</div>
</body>
</html>

View File

@@ -52,24 +52,38 @@
var in_options = {
'internalProjection': map.baseLayer.projection,
'externalProjection': new OpenLayers.Projection(OpenLayers.Util.getElement("inproj").value)
}
};
var out_options = {
'internalProjection': map.baseLayer.projection,
'externalProjection': new OpenLayers.Projection(OpenLayers.Util.getElement("outproj").value)
}
};
var gmlOptions = {
featureType: "feature",
featureNS: "http://example.com/feature"
};
var gmlOptionsIn = OpenLayers.Util.extend(
OpenLayers.Util.extend({}, gmlOptions),
in_options
);
var gmlOptionsOut = OpenLayers.Util.extend(
OpenLayers.Util.extend({}, gmlOptions),
out_options
);
formats = {
'in': {
wkt: new OpenLayers.Format.WKT(in_options),
geojson: new OpenLayers.Format.GeoJSON(in_options),
georss: new OpenLayers.Format.GeoRSS(in_options),
gml: new OpenLayers.Format.GML(in_options),
gml2: new OpenLayers.Format.GML.v2(gmlOptionsIn),
gml3: new OpenLayers.Format.GML.v3(gmlOptionsIn),
kml: new OpenLayers.Format.KML(in_options)
},
'out': {
wkt: new OpenLayers.Format.WKT(out_options),
geojson: new OpenLayers.Format.GeoJSON(out_options),
georss: new OpenLayers.Format.GeoRSS(out_options),
gml: new OpenLayers.Format.GML(out_options),
gml2: new OpenLayers.Format.GML.v2(gmlOptionsOut),
gml3: new OpenLayers.Format.GML.v3(gmlOptionsOut),
kml: new OpenLayers.Format.KML(out_options)
}
};
@@ -169,7 +183,8 @@
<option value="geojson" selected="selected">GeoJSON</option>
<option value="kml">KML</option>
<option value="georss">GeoRSS</option>
<option value="gml">GML</option>
<option value="gml2">GML (v2)</option>
<option value="gml3">GML (v3)</option>
<option value="wkt">Well-Known Text (WKT)</option>
</select>
&nbsp;

View File

@@ -45,7 +45,7 @@
// (only if your wfs doens't support your map projection)
var wfs = layer = new OpenLayers.Layer.WFS(
"States (SVG)",
"http://sigma.openplans.org:8080/geoserver/ows",
"http://sigma.openplans.org/geoserver/ows",
{typename: 'topp:states'},
{
typename: 'states',
@@ -60,7 +60,7 @@
var wfs = layer = new OpenLayers.Layer.WFS(
"States (Canvas)",
"http://sigma.openplans.org:8080/geoserver/ows",
"http://sigma.openplans.org/geoserver/ows",
{typename: 'topp:states'},
{
typename: 'states',

88
lib/Gears/gears_init.js Normal file
View File

@@ -0,0 +1,88 @@
/*
* Copyright 2007, Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of Google Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Sets up google.gears.*, which is *the only* supported way to access Gears.
*
* Circumvent this file at your own risk!
*
* In the future, Gears may automatically define google.gears.* without this
* file. Gears may use these objects to transparently fix bugs and compatibility
* issues. Applications that use the code below will continue to work seamlessly
* when that happens.
*/
(function() {
// We are already defined. Hooray!
if (window.google && google.gears) {
return;
}
var factory = null;
// Firefox
if (typeof GearsFactory != 'undefined') {
factory = new GearsFactory();
} else {
// IE
try {
factory = new ActiveXObject('Gears.Factory');
// privateSetGlobalObject is only required and supported on WinCE.
if (factory.getBuildInfo().indexOf('ie_mobile') != -1) {
factory.privateSetGlobalObject(this);
}
} catch (e) {
// Safari
if ((typeof navigator.mimeTypes != 'undefined')
&& navigator.mimeTypes["application/x-googlegears"]) {
factory = document.createElement("object");
factory.style.display = "none";
factory.width = 0;
factory.height = 0;
factory.type = "application/x-googlegears";
document.documentElement.appendChild(factory);
}
}
}
// *Do not* define any objects if Gears is not installed. This mimics the
// behavior of Gears defining the objects in the future.
if (!factory) {
return;
}
// Now set up the objects, being careful not to overwrite anything.
//
// Note: In Internet Explorer for Windows Mobile, you can't add properties to
// the window object. However, global objects are automatically added as
// properties of the window object in all browsers.
if (!window.google) {
google = {};
}
if (!google.gears) {
google.gears = {factory: factory};
}
})();

View File

@@ -83,6 +83,7 @@
"OpenLayers/Tween.js",
"Rico/Corner.js",
"Rico/Color.js",
"Gears/gears_init.js",
"OpenLayers/Ajax.js",
"OpenLayers/Request.js",
"OpenLayers/Request/XMLHttpRequest.js",
@@ -164,6 +165,7 @@
"OpenLayers/Control/Panel.js",
"OpenLayers/Control/SelectFeature.js",
"OpenLayers/Control/NavigationHistory.js",
"OpenLayers/Control/Measure.js",
"OpenLayers/Geometry.js",
"OpenLayers/Geometry/Rectangle.js",
"OpenLayers/Geometry/Collection.js",
@@ -184,8 +186,13 @@
"OpenLayers/Layer/Vector.js",
"OpenLayers/Strategy.js",
"OpenLayers/Strategy/Fixed.js",
"OpenLayers/Strategy/Cluster.js",
"OpenLayers/Strategy/Paging.js",
"OpenLayers/Strategy/BBOX.js",
"OpenLayers/Protocol.js",
"OpenLayers/Protocol/HTTP.js",
"OpenLayers/Protocol/SQL.js",
"OpenLayers/Protocol/SQL/Gears.js",
"OpenLayers/Layer/PointTrack.js",
"OpenLayers/Layer/GML.js",
"OpenLayers/Style.js",
@@ -199,6 +206,9 @@
"OpenLayers/Format.js",
"OpenLayers/Format/XML.js",
"OpenLayers/Format/GML.js",
"OpenLayers/Format/GML/Base.js",
"OpenLayers/Format/GML/v2.js",
"OpenLayers/Format/GML/v3.js",
"OpenLayers/Format/KML.js",
"OpenLayers/Format/GeoRSS.js",
"OpenLayers/Format/WFS.js",

View File

@@ -340,7 +340,7 @@ if (!Number.prototype.limitSigDigs) {
*/
Number.prototype.limitSigDigs = function(sig) {
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
{'newMethod':'OpenLayers.String.limitSigDigs'}));
{'newMethod':'OpenLayers.Number.limitSigDigs'}));
return OpenLayers.Number.limitSigDigs(this, sig);
};
}
@@ -409,7 +409,7 @@ if (!Function.prototype.bind) {
*/
Function.prototype.bind = function() {
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
{'newMethod':'OpenLayers.String.bind'}));
{'newMethod':'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);
@@ -430,7 +430,7 @@ if (!Function.prototype.bindAsEventListener) {
*/
Function.prototype.bindAsEventListener = function(object) {
OpenLayers.Console.warn(OpenLayers.i18n("methodDeprecated",
{'newMethod':'OpenLayers.String.bindAsEventListener'}));
{'newMethod':'OpenLayers.Function.bindAsEventListener'}));
return OpenLayers.Function.bindAsEventListener(this, object);
};
}

View File

@@ -233,10 +233,10 @@ OpenLayers.Console = {
* 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, len=scripts.length; i<len; ++i) {
if(scripts[i].src.indexOf("firebug.js") != -1) {
var scripts = document.getElementsByTagName("script");
for(var i=0, len=scripts.length; i<len; ++i) {
if(scripts[i].src.indexOf("firebug.js") != -1) {
if(console) {
OpenLayers.Util.extend(OpenLayers.Console, console);
break;
}

View File

@@ -10,6 +10,9 @@
* Class: OpenLayers.Control.Attribution
* Add attribution from layers to the map display. Uses 'attribution' property
* of each layer.
*
* Inherits from:
* - <OpenLayers.Control>
*/
OpenLayers.Control.Attribution =
OpenLayers.Class(OpenLayers.Control, {

View File

@@ -13,6 +13,9 @@
/**
* Class: OpenLayers.Control.EditingToolbar
*
* Inherits from:
* - <OpenLayers.Control.Panel>
*/
OpenLayers.Control.EditingToolbar = OpenLayers.Class(
OpenLayers.Control.Panel, {

View File

@@ -9,6 +9,9 @@
/**
* Class: OpenLayers.Control.MousePosition
*
* Inherits from:
* - <OpenLayers.Control>
*/
OpenLayers.Control.MousePosition = OpenLayers.Class(OpenLayers.Control, {

View File

@@ -52,7 +52,7 @@ OpenLayers.Control.Navigation = OpenLayers.Class(OpenLayers.Control, {
* APIProperty: handleRightClicks
* {Boolean} Whether or not to handle right clicks. Default is false.
*/
handleRightClicks: true,
handleRightClicks: false,
/**
* Constructor: OpenLayers.Control.Navigation

View File

@@ -1,9 +1,16 @@
/* 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.Pan
*
* Inherits from:
* - <OpenLayers.Control>
*/
OpenLayers.Control.Pan = OpenLayers.Class(OpenLayers.Control, {

View File

@@ -13,7 +13,9 @@
* <!--[if lte IE 6]>
* <link rel="stylesheet" href="../theme/default/ie6-style.css" type="text/css" />
* <![endif]-->
*
*
* Inherits from:
* - <OpenLayers.Control.Panel>
*/
OpenLayers.Control.PanPanel = OpenLayers.Class(OpenLayers.Control.Panel, {

View File

@@ -168,8 +168,6 @@ OpenLayers.Control.Permalink = OpenLayers.Class(OpenLayers.Control, {
*/
createParams: function(center, zoom, layers) {
center = center || this.map.getCenter();
zoom = zoom || this.map.getZoom();
layers = layers || this.map.layers;
var params = OpenLayers.Util.getParameters(this.base);
@@ -177,8 +175,11 @@ OpenLayers.Control.Permalink = OpenLayers.Class(OpenLayers.Control, {
// Break out of this function, and simply return the params from the
// base link.
if (center) {
params.zoom = this.map.getZoom();
//zoom
params.zoom = zoom || this.map.getZoom();
//lon,lat
var lat = center.lat;
var lon = center.lon;
@@ -192,10 +193,12 @@ OpenLayers.Control.Permalink = OpenLayers.Class(OpenLayers.Control, {
}
params.lat = Math.round(lat*100000)/100000;
params.lon = Math.round(lon*100000)/100000;
//layers
layers = layers || this.map.layers;
params.layers = '';
for (var i=0, len=this.map.layers.length; i<len; i++) {
var layer = this.map.layers[i];
for (var i=0, len=layers.length; i<len; i++) {
var layer = layers[i];
if (layer.isBaseLayer) {
params.layers += (layer == this.map.baseLayer) ? "B" : "0";

View File

@@ -10,6 +10,7 @@
/**
* Class: OpenLayers.Control.Scale
* Display a small scale indicator on the map.
*
* Inherits from:
* - <OpenLayers.Control>
*/

View File

@@ -1,9 +1,16 @@
/* 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.ZoomIn
*
* Inherits from:
* - <OpenLayers.Control>
*/
OpenLayers.Control.ZoomIn = OpenLayers.Class(OpenLayers.Control, {

View File

@@ -1,9 +1,16 @@
/* 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.ZoomOut
*
* Inherits from:
* - <OpenLayers.Control>
*/
OpenLayers.Control.ZoomOut = OpenLayers.Class(OpenLayers.Control, {
@@ -23,4 +30,4 @@ OpenLayers.Control.ZoomOut = OpenLayers.Class(OpenLayers.Control, {
},
CLASS_NAME: "OpenLayers.Control.ZoomOut"
});
});

View File

@@ -1,3 +1,7 @@
/* 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/Panel.js
* @requires OpenLayers/Control/ZoomIn.js
@@ -16,6 +20,8 @@
* <link rel="stylesheet" href="../theme/default/ie6-style.css" type="text/css" />
* <![endif]-->
*
* Inherits from:
* - <OpenLayers.Control.Panel>
*/
OpenLayers.Control.ZoomPanel = OpenLayers.Class(OpenLayers.Control.Panel, {

View File

@@ -8,7 +8,7 @@
/**
* Class: OpenLayers.Control.ZoomToMaxExtent
* Imlements a very simple button control. Designed to be used with a
* Implements a very simple button control. Designed to be used with a
* <OpenLayers.Control.Panel>.
*
* Inherits from:

View File

@@ -144,7 +144,7 @@ OpenLayers.Filter.Comparison = OpenLayers.Class(OpenLayers.Filter, {
escapeChar = escapeChar ? escapeChar : "!";
this.value = this.value.replace(
new RegExp("\\"+escapeChar+"(.|$)", "g"), "\\$1")
new RegExp("\\"+escapeChar+"(.|$)", "g"), "\\$1");
this.value = this.value.replace(
new RegExp("\\"+singleChar, "g"), ".");
this.value = this.value.replace(

View File

@@ -13,6 +13,12 @@
*/
OpenLayers.Format = OpenLayers.Class({
/**
* Property: options
* {Object} A reference to options passed to the constructor.
*/
options: null,
/**
* APIProperty: externalProjection
* {<OpenLayers.Projection>} When passed a externalProjection and
@@ -54,6 +60,14 @@ OpenLayers.Format = OpenLayers.Class({
*/
initialize: function(options) {
OpenLayers.Util.extend(this, options);
this.options = options;
},
/**
* APIMethod: destroy
* Clean up.
*/
destroy: function() {
},
/**

View File

@@ -59,7 +59,7 @@ OpenLayers.Format.Filter.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
* {<OpenLayers.Filter>} A filter object.
*/
read: function(data) {
var obj = {}
var obj = {};
var filter = this.readers.ogc["Filter"].apply(this, [data, obj]);
return obj.filter;
},

View File

@@ -0,0 +1,517 @@
/* 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/Format/XML.js
* @requires OpenLayers/Format/GML.js
*/
/**
* Class: OpenLayers.Format.GML.Base
* Superclass for GML parsers.
*
* Inherits from:
* - <OpenLayers.Format.XML>
*/
OpenLayers.Format.GML.Base = OpenLayers.Class(OpenLayers.Format.XML, {
/**
* Property: namespaces
* {Object} Mapping of namespace aliases to namespace URIs.
*/
namespaces: {
gml: "http://www.opengis.net/gml",
xlink: "http://www.w3.org/1999/xlink",
xsi: "http://www.w3.org/2001/XMLSchema-instance",
wfs: "http://www.opengis.net/wfs" // this is a convenience for reading wfs:FeatureCollection
},
/**
* Property: defaultPrefix
*/
defaultPrefix: "gml",
/**
* Property: schemaLocation
* {String} Schema location for a particular minor version.
*/
schemaLocation: null,
/**
* APIProperty: featureType
* {String} The local (without prefix) feature typeName.
*/
featureType: null,
/**
* APIProperty: featureNS
* {String} The feature namespace. Must be set in the options at
* construction.
*/
featureNS: null,
/**
* APIProperty: geometry
* {String} Name of geometry element. Defaults to "geometry".
*/
geometryName: "geometry",
/**
* APIProperty: extractAttributes
* {Boolean} Extract attributes from GML. Default is true.
*/
extractAttributes: true,
/**
* APIProperty: srsName
* {String} URI for spatial reference system. This is optional for
* single part geometries and mandatory for collections and multis.
* If set, the srsName attribute will be written for all geometries.
* Default is null.
*/
srsName: null,
/**
* APIProperty: xy
* {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
* Changing is not recommended, a new Format should be instantiated.
*/
xy: true,
/**
* Property: regExes
* Compiled regular expressions for manipulating strings.
*/
regExes: {
trimSpace: (/^\s*|\s*$/g),
removeSpace: (/\s*/g),
splitSpace: (/\s+/),
trimComma: (/\s*,\s*/g)
},
/**
* Constructor: OpenLayers.Format.GML.Base
* Instances of this class are not created directly. Use the
* <OpenLayers.Format.GML.v2> or <OpenLayers.Format.GML.v3> constructor
* instead.
*
* Parameters:
* options - {Object} An optional object whose properties will be set on
* this instance.
*
* Valid options properties:
* featureType - {String} Local (without prefix) feature typeName (required).
* featureNS - {String} Feature namespace (required).
* geometryName - {String} Geometry element name.
*/
initialize: function(options) {
OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
this.setNamespace("feature", options.featureNS);
},
/**
* Method: read
*
* Parameters:
* data - {DOMElement} A gml:featureMember element, a gml:featureMembers
* element, or an element containing either of the above at any level.
*
* Returns:
* {Array(<OpenLayers.Feature.Vector>)} An array of features.
*/
read: function(data) {
if(typeof data == "string") {
data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
}
if(data && data.nodeType == 9) {
data = data.documentElement;
}
var features = [];
this.readNode(data, {features: features});
if(features.length == 0) {
// look for gml:featureMember elements
var elements = this.getElementsByTagNameNS(
data, this.namespaces.gml, "featureMember"
);
if(elements.length) {
for(var i=0, len=elements.length; i<len; ++i) {
this.readNode(elements[i], {features: features});
}
} else {
// look for gml:featureMembers elements (this is v3, but does no harm here)
var elements = this.getElementsByTagNameNS(
data, this.namespaces.gml, "featureMembers"
);
if(elements.length) {
// there can be only one
this.readNode(elements[0], {features: features});
}
}
}
return features;
},
/**
* Property: readers
* Contains public functions, grouped by namespace prefix, that will
* be applied when a namespaced node is found matching the function
* name. The function will be applied in the scope of this parser
* with two arguments: the node being read and a context object passed
* from the parent.
*/
readers: {
"gml": {
"featureMember": function(node, obj) {
this.readChildNodes(node, obj);
},
"featureMembers": function(node, obj) {
this.readChildNodes(node, obj);
},
"Point": function(node, container) {
var obj = {points: []};
this.readChildNodes(node, obj);
if(!container.components) {
container.components = [];
}
container.components.push(obj.points[0]);
},
"coordinates": function(node, obj) {
var str = this.concatChildValues(node).replace(
this.regExes.trimSpace, ""
);
str = str.replace(this.regExes.trimComma, ",");
var pointList = str.split(this.regExes.splitSpace);
var coords;
var numPoints = pointList.length;
var points = new Array(numPoints);
for(var i=0; i<numPoints; ++i) {
coords = pointList[i].split(",");
if (this.xy) {
points[i] = new OpenLayers.Geometry.Point(
coords[0], coords[1], coords[2]
);
} else {
points[i] = new OpenLayers.Geometry.Point(
coords[1], coords[0], coords[2]
);
}
}
obj.points = points;
},
"coord": function(node, obj) {
var coord = {};
this.readChildNodes(node, coord);
if(!obj.points) {
obj.points = [];
}
obj.points.push(new OpenLayers.Geometry.Point(
coord.x, coord.y, coord.z
));
},
"X": function(node, coord) {
coord.x = this.getChildValue(node);
},
"Y": function(node, coord) {
coord.y = this.getChildValue(node);
},
"Z": function(node, coord) {
coord.z = this.getChildValue(node);
},
"MultiPoint": function(node, container) {
var obj = {components: []};
this.readChildNodes(node, obj);
container.components = [
new OpenLayers.Geometry.MultiPoint(obj.components)
];
},
"pointMember": function(node, obj) {
this.readChildNodes(node, obj);
},
"LineString": function(node, container) {
var obj = {};
this.readChildNodes(node, obj);
if(!container.components) {
container.components = [];
}
container.components.push(
new OpenLayers.Geometry.LineString(obj.points)
);
},
"MultiLineString": function(node, container) {
var obj = {components: []};
this.readChildNodes(node, obj);
container.components = [
new OpenLayers.Geometry.MultiLineString(obj.components)
];
},
"lineStringMember": function(node, obj) {
this.readChildNodes(node, obj);
},
"Polygon": function(node, container) {
var obj = {outer: null, inner: []};
this.readChildNodes(node, obj);
obj.inner.unshift(obj.outer);
if(!container.components) {
container.components = [];
}
container.components.push(
new OpenLayers.Geometry.Polygon(obj.inner)
);
},
"LinearRing": function(node, obj) {
var container = {};
this.readChildNodes(node, container);
obj.components = [new OpenLayers.Geometry.LinearRing(
container.points
)];
},
"MultiPolygon": function(node, container) {
var obj = {components: []};
this.readChildNodes(node, obj);
container.components = [
new OpenLayers.Geometry.MultiPolygon(obj.components)
];
},
"polygonMember": function(node, obj) {
this.readChildNodes(node, obj);
},
"GeometryCollection": function(node, container) {
var obj = {components: []};
this.readChildNodes(node, obj);
container.components = [
new OpenLayers.Geometry.Collection(obj.components)
];
},
"geometryMember": function(node, obj) {
this.readChildNodes(node, obj);
}
},
"feature": {
"*": function(node, obj) {
// The node can either be named like the featureType, or it
// can be a child of the feature:featureType. Children can be
// geometry or attributes.
var name;
var local = node.localName || node.nodeName.split(":").pop();
if(local == this.featureType) {
name = "_typeName";
} else {
// Assume attribute elements have one child node and that the child
// is a text node. Otherwise assume it is a geometry node.
if(node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
if(this.extractAttributes) {
name = "_attribute";
}
} else {
name = "_geometry";
}
}
if(name) {
this.readers.feature[name].apply(this, [node, obj]);
}
},
"_typeName": function(node, obj) {
var container = {components: [], attributes: {}};
this.readChildNodes(node, container);
var feature = new OpenLayers.Feature.Vector(
container.components[0], container.attributes
);
var fid = node.getAttribute("fid") ||
this.getAttributeNS(node, this.namespaces["gml"], "id");
if(fid) {
feature.fid = fid;
}
if(this.internalProjection && this.externalProjection &&
feature.geometry) {
feature.geometry.transform(
this.externalProjection, this.internalProjection
);
}
obj.features.push(feature);
},
"_geometry": function(node, obj) {
this.readChildNodes(node, obj);
},
"_attribute": function(node, obj) {
var local = node.localName || node.nodeName.split(":").pop();
var value = this.getChildValue(node);
obj.attributes[local] = value;
}
},
"wfs": {
"FeatureCollection": function(node, obj) {
this.readChildNodes(node, obj);
}
}
},
/**
* Method: write
*
* Parameters:
* features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector}
* An array of features or a single feature.
*
* Returns:
* {String} Given an array of features, a doc with a gml:featureMembers
* element will be returned. Given a single feature, a doc with a
* gml:featureMember element will be returned.
*/
write: function(features) {
var name;
if(features instanceof Array) {
name = "featureMembers";
} else {
name = "featureMember";
}
var root = this.writeNode("gml:" + name, features);
this.setAttributeNS(
root, this.namespaces["xsi"],
"xsi:schemaLocation", this.schemaLocation
);
return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
},
/**
* Property: writers
* As a compliment to the readers property, this structure contains public
* writing functions grouped by namespace alias and named like the
* node names they produce.
*/
writers: {
"gml": {
"featureMember": function(feature) {
var node = this.createElementNSPlus("gml:featureMember");
this.writeNode("feature:_typeName", feature, node);
return node;
},
"MultiPoint": function(geometry) {
var node = this.createElementNSPlus("gml:MultiPoint");
for(var i=0; i<geometry.components.length; ++i) {
this.writeNode("pointMember", geometry.components[i], node);
}
return node;
},
"pointMember": function(geometry) {
var node = this.createElementNSPlus("gml:pointMember");
this.writeNode("Point", geometry, node);
return node;
},
"MultiLineString": function(geometry) {
var node = this.createElementNSPlus("gml:MultiLineString");
for(var i=0; i<geometry.components.length; ++i) {
this.writeNode("lineStringMember", geometry.components[i], node);
}
return node;
},
"lineStringMember": function(geometry) {
var node = this.createElementNSPlus("gml:lineStringMember");
this.writeNode("LineString", geometry, node);
return node;
},
"MultiPolygon": function(geometry) {
var node = this.createElementNSPlus("gml:MultiPolygon");
for(var i=0; i<geometry.components.length; ++i) {
this.writeNode(
"polygonMember", geometry.components[i], node
);
}
return node;
},
"polygonMember": function(geometry) {
var node = this.createElementNSPlus("gml:polygonMember");
this.writeNode("Polygon", geometry, node);
return node;
},
"GeometryCollection": function(geometry) {
var node = this.createElementNSPlus("gml:GeometryCollection");
for(var i=0, len=geometry.components.length; i<len; ++i) {
this.writeNode("geometryMember", geometry.components[i], node);
}
return node;
},
"geometryMember": function(geometry) {
var node = this.createElementNSPlus("gml:geometryMember");
var child = this.writeNode("feature:_geometry", geometry);
node.appendChild(child.firstChild);
return node;
}
},
"feature": {
"_typeName": function(feature) {
var node = this.createElementNSPlus("feature:" + this.featureType, {
attributes: {fid: feature.fid}
});
if(feature.geometry) {
this.writeNode("feature:_geometry", feature.geometry, node);
}
for(var name in feature.attributes) {
var value = feature.attributes[name];
if(value != null) {
this.writeNode(
"feature:_attribute",
{name: name, value: value}, node
)
}
}
return node;
},
"_geometry": function(geometry) {
if(this.externalProjection && this.internalProjection) {
geometry = geometry.clone().transform(
this.internalProjection, this.externalProjection
);
}
var node = this.createElementNSPlus(
"feature:" + this.geometryName
);
var type = this.geometryTypes[geometry.CLASS_NAME];
var child = this.writeNode("gml:" + type, geometry, node);
if(this.srsName) {
child.setAttribute("srsName", this.srsName);
}
return node;
},
"_attribute": function(obj) {
return this.createElementNSPlus("feature:" + obj.name, {
value: obj.value
});
}
},
"wfs": {
"FeatureCollection": function(features) {
/**
* This is only here because GML2 only describes abstract
* feature collections. Typically, you would not be using
* the GML format to write wfs elements. This just provides
* some way to write out lists of features. GML3 defines the
* featureMembers element, so that is used by default instead.
*/
var node = this.createElementNSPlus("wfs:FeatureCollection");
for(var i=0, len=features.length; i<len; ++i) {
this.writeNode("gml:featureMember", features[i], node);
}
return node;
}
}
},
/**
* Property: geometryTypes
* {Object} Maps OpenLayers geometry class names to GML element names.
*/
geometryTypes: {
"OpenLayers.Geometry.Point": "Point",
"OpenLayers.Geometry.MultiPoint": "MultiPoint",
"OpenLayers.Geometry.LineString": "LineString",
"OpenLayers.Geometry.MultiLineString": "MultiLineString",
"OpenLayers.Geometry.Polygon": "Polygon",
"OpenLayers.Geometry.MultiPolygon": "MultiPolygon",
"OpenLayers.Geometry.Collection": "GeometryCollection"
},
CLASS_NAME: "OpenLayers.Format.GML.Base"
});

View File

@@ -0,0 +1,192 @@
/* 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/Format/GML/Base.js
*/
/**
* Class: OpenLayers.Format.GML.v2
* Parses GML version 2.
*
* Inherits from:
* - <OpenLayers.Format.GML.Base>
*/
OpenLayers.Format.GML.v2 = OpenLayers.Class(OpenLayers.Format.GML.Base, {
/**
* Property: schemaLocation
* {String} Schema location for a particular minor version.
*/
schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd",
/**
* Constructor: OpenLayers.Format.GML.v2
* Create a parser for GML v2.
*
* Parameters:
* options - {Object} An optional object whose properties will be set on
* this instance.
*
* Valid options properties:
* featureType - {String} Local (without prefix) feature typeName (required).
* featureNS - {String} Feature namespace (required).
* geometryName - {String} Geometry element name.
*/
initialize: function(options) {
OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]);
},
/**
* Property: readers
* Contains public functions, grouped by namespace prefix, that will
* be applied when a namespaced node is found matching the function
* name. The function will be applied in the scope of this parser
* with two arguments: the node being read and a context object passed
* from the parent.
*/
readers: {
"gml": OpenLayers.Util.applyDefaults({
"outerBoundaryIs": function(node, container) {
var obj = {};
this.readChildNodes(node, obj);
container.outer = obj.components[0];
},
"innerBoundaryIs": function(node, container) {
var obj = {};
this.readChildNodes(node, obj);
container.inner.push(obj.components[0]);
},
"Box": function(node, container) {
var obj = {};
this.readChildNodes(node, obj);
if(!container.components) {
container.components = [];
}
var min = obj.points[0];
var max = obj.points[1];
container.components.push(
new OpenLayers.Bounds(min.x, min.y, max.x, max.y)
);
}
}, OpenLayers.Format.GML.Base.prototype.readers["gml"]),
"feature": OpenLayers.Format.GML.Base.prototype.readers["feature"],
"wfs": OpenLayers.Format.GML.Base.prototype.readers["wfs"]
},
/**
* Method: write
*
* Parameters:
* features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector}
* An array of features or a single feature.
*
* Returns:
* {String} Given an array of features, a doc with a gml:featureMembers
* element will be returned. Given a single feature, a doc with a
* gml:featureMember element will be returned.
*/
write: function(features) {
var name;
if(features instanceof Array) {
// GML2 only has abstract feature collections
// wfs provides a feature collection from a well-known schema
name = "wfs:FeatureCollection";
} else {
name = "gml:featureMember";
}
var root = this.writeNode(name, features);
this.setAttributeNS(
root, this.namespaces["xsi"],
"xsi:schemaLocation", this.schemaLocation
);
return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
},
/**
* Property: writers
* As a compliment to the readers property, this structure contains public
* writing functions grouped by namespace alias and named like the
* node names they produce.
*/
writers: {
"gml": OpenLayers.Util.applyDefaults({
"Point": function(geometry) {
var node = this.createElementNSPlus("gml:Point");
this.writeNode("coordinates", [geometry], node);
return node;
},
"coordinates": function(points) {
var numPoints = points.length;
var parts = new Array(numPoints);
var point;
for(var i=0; i<numPoints; ++i) {
point = points[i];
if(this.xy) {
parts[i] = point.x + "," + point.y;
} else {
parts[i] = point.y + "," + point.x;
}
if(point.z != undefined) { // allow null or undefined
parts[i] += "," + point.z;
}
}
return this.createElementNSPlus("gml:coordinates", {
attributes: {
decimal: ".", cs: ",", ts: " "
},
value: (numPoints == 1) ? parts[0] : parts.join(" ")
});
},
"LineString": function(geometry) {
var node = this.createElementNSPlus("gml:LineString");
this.writeNode("coordinates", geometry.components, node);
return node;
},
"Polygon": function(geometry) {
var node = this.createElementNSPlus("gml:Polygon");
this.writeNode("outerBoundaryIs", geometry.components[0], node);
for(var i=1; i<geometry.components.length; ++i) {
this.writeNode(
"innerBoundaryIs", geometry.components[i], node
);
}
return node;
},
"outerBoundaryIs": function(ring) {
var node = this.createElementNSPlus("gml:outerBoundaryIs");
this.writeNode("LinearRing", ring, node);
return node;
},
"innerBoundaryIs": function(ring) {
var node = this.createElementNSPlus("gml:innerBoundaryIs");
this.writeNode("LinearRing", ring, node);
return node;
},
"LinearRing": function(ring) {
var node = this.createElementNSPlus("gml:LinearRing");
this.writeNode("coordinates", ring.components, node);
return node;
},
"Box": function(bounds) {
var node = this.createElementNSPlus("gml:Box");
this.writeNode("coordinates", [
{x: bounds.left, y: bounds.bottom},
{x: bounds.right, y: bounds.top}
], node);
// srsName attribute is optional for gml:Box
if(this.srsName) {
node.setAttribute("srsName", this.srsName);
}
return node;
}
}, OpenLayers.Format.GML.Base.prototype.writers["gml"]),
"feature": OpenLayers.Format.GML.Base.prototype.writers["feature"],
"wfs": OpenLayers.Format.GML.Base.prototype.writers["wfs"]
},
CLASS_NAME: "OpenLayers.Format.GML.v2"
});

View File

@@ -0,0 +1,287 @@
/* 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/Format/GML/Base.js
*/
/**
* Class: OpenLayers.Format.GML.v3
* Parses GML version 3.
*
* Inherits from:
* - <OpenLayers.Format.GML.Base>
*/
OpenLayers.Format.GML.v3 = OpenLayers.Class(OpenLayers.Format.GML.Base, {
/**
* Property: schemaLocation
* {String} Schema location for a particular minor version. The writers
* conform with the Simple Features Profile for GML.
*/
schemaLocation: "http://www.opengis.net/gml http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/1.0.0/gmlsf.xsd",
/**
* Constructor: OpenLayers.Format.GML.v3
* Create a parser for GML v3.
*
* Parameters:
* options - {Object} An optional object whose properties will be set on
* this instance.
*
* Valid options properties:
* featureType - {String} Local (without prefix) feature typeName (required).
* featureNS - {String} Feature namespace (required).
* geometryName - {String} Geometry element name.
*/
initialize: function(options) {
OpenLayers.Format.GML.Base.prototype.initialize.apply(this, [options]);
},
/**
* Property: readers
* Contains public functions, grouped by namespace prefix, that will
* be applied when a namespaced node is found matching the function
* name. The function will be applied in the scope of this parser
* with two arguments: the node being read and a context object passed
* from the parent.
*/
readers: {
"gml": OpenLayers.Util.applyDefaults({
"featureMembers": function(node, obj) {
this.readChildNodes(node, obj);
},
"pos": function(node, obj) {
var str = this.getChildValue(node).replace(
this.regExes.trimSpace, ""
);
var coords = str.split(this.regExes.splitSpace);
var point;
if(this.xy) {
point = new OpenLayers.Geometry.Point(
coords[0], coords[1], coords[2]
);
} else {
point = new OpenLayers.Geometry.Point(
coords[1], coords[0], coords[2]
);
}
obj.points = [point];
},
"posList": function(node, obj) {
var str = this.concatChildValues(node).replace(
this.regExes.trimSpace, ""
);
var coords = str.split(this.regExes.splitSpace);
var dim = parseInt(node.getAttribute("dimension")) || 2;
var j, x, y, z;
var numPoints = coords.length / dim;
var points = new Array(numPoints);
for(var i=0, len=coords.length; i<len; i += dim) {
x = coords[i];
y = coords[i+1];
z = (dim == 2) ? undefined : coords[i+2];
if (this.xy) {
points[i/dim] = new OpenLayers.Geometry.Point(x, y, z);
} else {
points[i/dim] = new OpenLayers.Geometry.Point(y, x, z);
}
}
obj.points = points;
},
"exterior": function(node, container) {
var obj = {};
this.readChildNodes(node, obj);
container.outer = obj.components[0];
},
"interior": function(node, container) {
var obj = {};
this.readChildNodes(node, obj);
container.inner.push(obj.components[0]);
},
"MultiSurface": function(node, container) {
var obj = {components: []};
this.readChildNodes(node, obj);
if(obj.components.length > 0) {
container.components = [
new OpenLayers.Geometry.MultiPolygon(obj.components)
];
}
},
"surfaceMember": function(node, obj) {
this.readChildNodes(node, obj);
},
"surfaceMembers": function(node, obj) {
this.readChildNodes(node, obj);
},
"pointMembers": function(node, obj) {
this.readChildNodes(node, obj);
},
"lineStringMembers": function(node, obj) {
this.readChildNodes(node, obj);
},
"polygonMembers": function(node, obj) {
this.readChildNodes(node, obj);
},
"geometryMembers": function(node, obj) {
this.readChildNodes(node, obj);
},
"Envelope": function(node, container) {
var obj = {points: new Array(2)};
this.readChildNodes(node, obj);
if(!container.components) {
container.components = [];
}
var min = obj.points[0];
var max = obj.points[1];
container.components.push(
new OpenLayers.Bounds(min.x, min.y, max.x, max.y)
);
},
"lowerCorner": function(node, container) {
var obj = {};
this.readChildNodes(node, obj)
container.points[0] = obj.points[0];
},
"upperCorner": function(node, container) {
var obj = {};
this.readChildNodes(node, obj)
container.points[1] = obj.points[0];
}
}, OpenLayers.Format.GML.Base.prototype.readers["gml"]),
"feature": OpenLayers.Format.GML.Base.prototype.readers["feature"],
"wfs": OpenLayers.Format.GML.Base.prototype.readers["wfs"]
},
/**
* Method: write
*
* Parameters:
* features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector}
* An array of features or a single feature.
*
* Returns:
* {String} Given an array of features, a doc with a gml:featureMembers
* element will be returned. Given a single feature, a doc with a
* gml:featureMember element will be returned.
*/
write: function(features) {
var name;
if(features instanceof Array) {
name = "featureMembers";
} else {
name = "featureMember";
}
var root = this.writeNode("gml:" + name, features);
this.setAttributeNS(
root, this.namespaces["xsi"],
"xsi:schemaLocation", this.schemaLocation
);
return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
},
/**
* Property: writers
* As a compliment to the readers property, this structure contains public
* writing functions grouped by namespace alias and named like the
* node names they produce.
*/
writers: {
"gml": OpenLayers.Util.applyDefaults({
"featureMembers": function(features) {
var node = this.createElementNSPlus("gml:featureMembers");
for(var i=0, len=features.length; i<len; ++i) {
this.writeNode("feature:_typeName", features[i], node);
}
return node;
},
"Point": function(geometry) {
var node = this.createElementNSPlus("gml:Point");
this.writeNode("pos", geometry, node);
return node;
},
"pos": function(point) {
// only 2d for simple features profile
var pos = (this.xy) ?
(point.x + " " + point.y) : (point.y + " " + point.x);
return this.createElementNSPlus("gml:pos", {
value: pos
});
},
"LineString": function(geometry) {
var node = this.createElementNSPlus("gml:LineString");
this.writeNode("posList", geometry.components, node);
return node;
},
"posList": function(points) {
// only 2d for simple features profile
var len = points.length;
var parts = new Array(len);
var point;
for(var i=0; i<len; ++i) {
point = points[i];
if(this.xy) {
parts[i] = point.x + " " + point.y;
} else {
parts[i] = point.y + " " + point.x;
}
}
return this.createElementNSPlus("gml:posList", {
value: parts.join(" ")
});
},
"Polygon": function(geometry) {
var node = this.createElementNSPlus("gml:Polygon");
this.writeNode("exterior", geometry.components[0], node);
for(var i=1, len=geometry.components.length; i<len; ++i) {
this.writeNode(
"interior", geometry.components[i], node
);
}
return node;
},
"exterior": function(ring) {
var node = this.createElementNSPlus("gml:exterior");
this.writeNode("LinearRing", ring, node);
return node;
},
"interior": function(ring) {
var node = this.createElementNSPlus("gml:interior");
this.writeNode("LinearRing", ring, node);
return node;
},
"LinearRing": function(ring) {
var node = this.createElementNSPlus("gml:LinearRing");
this.writeNode("posList", ring.components, node);
return node;
},
"Envelope": function(bounds) {
var node = this.createElementNSPlus("gml:Envelope");
this.writeNode("lowerCorner", bounds, node);
this.writeNode("upperCorner", bounds, node);
// srsName attribute is required for gml:Envelope
if(this.srsName) {
node.setAttribute("srsName", this.srsName);
}
return node;
},
"lowerCorner": function(bounds) {
var node = this.createElementNSPlus("gml:lowerCorner");
this.writeNode("pos", {x: bounds.left, y: bounds.bottom}, node);
return node;
},
"upperCorner": function(bounds) {
var node = this.createElementNSPlus("gml:upperCorner");
this.writeNode("pos", {x: bounds.right, y: bounds.top}, node);
return node;
}
}, OpenLayers.Format.GML.Base.prototype.writers["gml"]),
"feature": OpenLayers.Format.GML.Base.prototype.writers["feature"],
"wfs": OpenLayers.Format.GML.Base.prototype.writers["wfs"]
},
CLASS_NAME: "OpenLayers.Format.GML.v3"
});

View File

@@ -86,7 +86,7 @@ OpenLayers.Format.GPX = OpenLayers.Class(OpenLayers.Format.XML, {
var tracks = doc.getElementsByTagName("trk");
for (var i=0, len=tracks.length; i<len; i++) {
// Attributes are only in trk nodes, not trkseg nodes
var attrs = {}
var attrs = {};
if(this.extractAttributes) {
attrs = this.parseAttributes(tracks[i]);
}
@@ -104,7 +104,7 @@ OpenLayers.Format.GPX = OpenLayers.Class(OpenLayers.Format.XML, {
if(this.extractRoutes) {
var routes = doc.getElementsByTagName("rte");
for (var k=0, klen=routes.length; k<klen; k++) {
var attrs = {}
var attrs = {};
if(this.extractAttributes) {
attrs = this.parseAttributes(routes[k]);
}

View File

@@ -9,6 +9,9 @@
/**
* Class: OpenLayers.Format.WFS
* Read/Write WFS.
*
* Inherits from:
* - <OpenLayers.Format.GML>
*/
OpenLayers.Format.WFS = OpenLayers.Class(OpenLayers.Format.GML, {

View File

@@ -19,6 +19,46 @@
*/
OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
/**
* Property: namespaces
* {Object} Mapping of namespace aliases to namespace URIs. Properties
* of this object should not be set individually. Read-only. All
* XML subclasses should have their own namespaces object. Use
* <setNamespace> to add or set a namespace alias after construction.
*/
namespaces: null,
/**
* Property: namespaceAlias
* {Object} Mapping of namespace URI to namespace alias. This object
* is read-only. Use <setNamespace> to add or set a namespace alias.
*/
namespaceAlias: null,
/**
* Property: defaultPrefix
* {String} The default namespace alias for creating element nodes.
*/
defaultPrefix: null,
/**
* Property: readers
* Contains public functions, grouped by namespace prefix, that will
* be applied when a namespaced node is found matching the function
* name. The function will be applied in the scope of this parser
* with two arguments: the node being read and a context object passed
* from the parent.
*/
readers: {},
/**
* Property: writers
* As a compliment to the <readers> property, this structure contains public
* writing functions grouped by namespace alias and named like the
* node names they produce.
*/
writers: {},
/**
* Property: xmldom
* {XMLDom} If this browser uses ActiveX, this will be set to a XMLDOM
@@ -44,6 +84,34 @@ OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
this.xmldom = new ActiveXObject("Microsoft.XMLDOM");
}
OpenLayers.Format.prototype.initialize.apply(this, [options]);
// clone the namespace object and set all namespace aliases
this.namespaces = OpenLayers.Util.extend({}, this.namespaces);
this.namespaceAlias = {};
for(var alias in this.namespaces) {
this.namespaceAlias[this.namespaces[alias]] = alias;
}
},
/**
* APIMethod: destroy
* Clean up.
*/
destroy: function() {
this.xmldom = null;
OpenLayers.Format.prototype.destroy.apply(this, arguments);
},
/**
* Method: setNamespace
* Set a namespace alias and URI for the format.
*
* Parameters:
* alias - {String} The namespace alias (prefix).
* uri - {String} The namespace URI.
*/
setNamespace: function(alias, uri) {
this.namespaces[alias] = uri;
this.namespaceAlias[uri] = alias;
},
/**
@@ -289,11 +357,12 @@ OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
* {String} The value of the first child of the given node.
*/
getChildValue: function(node, def) {
var value;
if (node && node.firstChild && node.firstChild.nodeValue) {
value = node.firstChild.nodeValue;
} else {
value = (def != undefined) ? def : "";
var value = def || "";
if(node) {
var child = node.firstChild;
if(child) {
value = child.nodeValue || value;
}
}
return value;
},
@@ -384,6 +453,172 @@ OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
}
},
/**
* Method: createElementNSPlus
* Shorthand for creating namespaced elements with optional attributes and
* child text nodes.
*
* Parameters:
* name - {String} The qualified node name.
* options - {Object} Optional object for node configuration.
*
* Valid options:
* uri - {String} Optional namespace uri for the element - supply a prefix
* instead if the namespace uri is a property of the format's namespace
* object.
* attributes - {Object} Optional attributes to be set using the
* <setAttributes> method.
* value - {String} Optional text to be appended as a text node.
*
* Returns:
* {Element} An element node.
*/
createElementNSPlus: function(name, options) {
options = options || {};
var loc = name.indexOf(":");
// order of prefix preference
// 1. in the uri option
// 2. in the prefix option
// 3. in the qualified name
// 4. from the defaultPrefix
var uri = options.uri || this.namespaces[options.prefix];
if(!uri) {
loc = name.indexOf(":");
uri = this.namespaces[name.substring(0, loc)];
}
if(!uri) {
uri = this.namespaces[this.defaultPrefix];
}
var node = this.createElementNS(uri, name);
if(options.attributes) {
this.setAttributes(node, options.attributes);
}
if(options.value) {
node.appendChild(this.createTextNode(options.value));
}
return node;
},
/**
* Method: setAttributes
* Set multiple attributes given key value pairs from an object.
*
* Parameters:
* node - {Element} An element node.
* obj - {Object || Array} An object whose properties represent attribute
* names and values represent attribute values. If an attribute name
* is a qualified name ("prefix:local"), the prefix will be looked up
* in the parsers {namespaces} object. If the prefix is found,
* setAttributeNS will be used instead of setAttribute.
*/
setAttributes: function(node, obj) {
var value, loc, alias, uri;
for(var name in obj) {
if(obj[name] != null && obj[name].toString) {
value = obj[name].toString();
// check for qualified attribute name ("prefix:local")
uri = this.namespaces[name.substring(0, name.indexOf(":"))] || null;
this.setAttributeNS(node, uri, name, value);
}
}
},
/**
* Method: readNode
* Shorthand for applying one of the named readers given the node
* namespace and local name. Readers take two args (node, obj) and
* generally extend or modify the second.
*
* Parameters:
* node - {DOMElement} The node to be read (required).
* obj - {Object} The object to be modified (optional).
*
* Returns:
* {Object} The input object, modified (or a new one if none was provided).
*/
readNode: function(node, obj) {
if(!obj) {
obj = {};
}
var group = this.readers[this.namespaceAlias[node.namespaceURI]];
if(group) {
var local = node.localName || node.nodeName.split(":").pop();
var reader = group[local] || group["*"];
if(reader) {
reader.apply(this, [node, obj]);
}
}
return obj;
},
/**
* Method: readChildNodes
* Shorthand for applying the named readers to all children of a node.
* For each child of type 1 (element), <readSelf> is called.
*
* Parameters:
* node - {DOMElement} The node to be read (required).
* obj - {Object} The object to be modified (optional).
*
* Returns:
* {Object} The input object, modified.
*/
readChildNodes: function(node, obj) {
if(!obj) {
obj = {};
}
var children = node.childNodes;
var child;
for(var i=0, len=children.length; i<len; ++i) {
child = children[i];
if(child.nodeType == 1) {
this.readNode(child, obj);
}
}
return obj;
},
/**
* Method: writeNode
* Shorthand for applying one of the named writers and appending the
* results to a node. If a qualified name is not provided for the
* second argument (and a local name is used instead), the namespace
* of the parent node will be assumed.
*
* Parameters:
* name - {String} The name of a node to generate. If a qualified name
* (e.g. "pre:Name") is used, the namespace prefix is assumed to be
* in the <writers> group. If a local name is used (e.g. "Name") then
* the namespace of the parent is assumed. If a local name is used
* and no parent is supplied, then the default namespace is assumed.
* obj - {Object} Structure containing data for the writer.
* parent - {DOMElement} Result will be appended to this node. If no parent
* is supplied, the node will not be appended to anything.
*
* Returns:
* {DOMElement} The child node.
*/
writeNode: function(name, obj, parent) {
var prefix, local;
var split = name.indexOf(":");
if(split > 0) {
prefix = name.substring(0, split);
local = name.substring(split + 1);
} else {
if(parent) {
prefix = this.namespaceAlias[parent.namespaceURI];
} else {
prefix = this.defaultPrefix;
}
local = name;
}
var child = this.writers[prefix][local].apply(this, [obj]);
if(parent) {
parent.appendChild(child);
}
return child;
},
CLASS_NAME: "OpenLayers.Format.XML"
});

View File

@@ -188,7 +188,7 @@ OpenLayers.Handler.Box = OpenLayers.Class(OpenLayers.Handler, {
xOffset: xOffset,
yOffset: yOffset,
newBoxModel: newBoxModel
}
};
}
return this.boxCharacteristics;
},

View File

@@ -159,7 +159,7 @@ OpenLayers.Layer.FixedZoomLevels = OpenLayers.Class({
// case (5) -- neither 'numZoomLevels' not 'maxZoomLevel' was
// set on either the layer or the map. So we just use the
// maximum limit as calculated by the layer's constants.
this.numZoomLevels = limitZoomLevels
this.numZoomLevels = limitZoomLevels;
}
//now that the 'numZoomLevels' is appropriately, safely set,

View File

@@ -5,6 +5,7 @@
/**
* @requires OpenLayers/Layer/Grid.js
* @requires OpenLayers/Tile/Image.js
*/
/**

View File

@@ -38,7 +38,12 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
* Supported map event types (in addition to those from <OpenLayers.Layer>):
* - *beforefeatureadded* Triggered before a feature is added. Listeners
* will receive an object with a *feature* property referencing the
* feature to be added.
* feature to be added. To stop the feature from being added, a
* listener should return false.
* - *beforefeaturesadded* Triggered before an array of features is added.
* Listeners will receive an object with a *features* property
* referencing the feature to be added. To stop the features from
* being added, a listener should return false.
* - *featureadded* Triggered after a feature is added. The event
* object passed to listeners will have a *feature* property with a
* reference to the added feature.
@@ -72,7 +77,8 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
* - *refresh* Triggered when something wants a strategy to ask the protocol
* for a new set of features.
*/
EVENT_TYPES: ["beforefeatureadded", "featureadded", "featuresadded",
EVENT_TYPES: ["beforefeatureadded", "beforefeaturesadded",
"featureadded", "featuresadded",
"beforefeatureremoved", "featureremoved", "featuresremoved",
"beforefeatureselected", "featureselected", "featureunselected",
"beforefeaturemodified", "featuremodified", "afterfeaturemodified",
@@ -407,19 +413,14 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
}
if(!zoomChanged && coordSysUnchanged) {
var unrenderedFeatures = {};
for(var i in this.unrenderedFeatures) {
var feature = this.unrenderedFeatures[i];
if(!this.drawFeature(feature)) {
unrenderedFeatures[i] = feature;
}
this.drawFeature(feature);
}
this.unrenderedFeatures = unrenderedFeatures;
}
}
if (!this.drawn || zoomChanged || !coordSysUnchanged) {
this.unrenderedFeatures = {};
this.drawn = true;
var feature;
for(var i=0, len=this.features.length; i<len; i++) {
@@ -429,9 +430,7 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
this.renderer.locked = false;
}
feature = this.features[i];
if (!this.drawFeature(feature)) {
this.unrenderedFeatures[feature.id] = feature;
};
this.drawFeature(feature);
}
}
},
@@ -450,6 +449,15 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
}
var notify = !options || !options.silent;
if(notify) {
var event = {features: features};
var ret = this.events.triggerEvent("beforefeaturesadded", event);
if(ret === false) {
return;
}
features = event.features;
}
for (var i=0, len=features.length; i<len; i++) {
if (i != (features.length - 1)) {
@@ -476,16 +484,15 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
}
if (notify) {
this.events.triggerEvent("beforefeatureadded", {
feature: feature
});
if(this.events.triggerEvent("beforefeatureadded",
{feature: feature}) === false) {
continue;
};
this.preFeatureInsert(feature);
}
if (this.drawn) {
if(!this.drawFeature(feature)) {
this.unrenderedFeatures[feature.id] = feature;
}
this.drawFeature(feature);
}
if (notify) {
@@ -603,10 +610,6 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
* Parameters:
* feature - {<OpenLayers.Feature.Vector>}
* style - {Object} Symbolizer hash or {String} renderIntent
*
* Returns:
* {Boolean} true if the renderer was able to draw the feature, false
* otherwise
*/
drawFeature: function(feature, style) {
if (typeof style != "object") {
@@ -618,7 +621,11 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
}
}
return this.renderer.drawFeature(feature, style);
if (!this.renderer.drawFeature(feature, style)) {
this.unrenderedFeatures[feature.id] = feature;
} else {
delete this.unrenderedFeatures[feature.id];
};
},
/**

View File

@@ -167,7 +167,14 @@ OpenLayers.Map = OpenLayers.Class({
/**
* Property: controls
* {Array(<OpenLayers.Control>)} List of controls associated with the map
* {Array(<OpenLayers.Control>)} List of controls associated with the map.
*
* If not provided in the map options at construction, the map will
* be given the following controls by default:
* - <OpenLayers.Control.Navigation>
* - <OpenLayers.Control.PanZoom>
* - <OpenLayers.Control.ArgParser>
* - <OpenLayers.Control.Attribution>
*/
controls: null,

View File

@@ -11,13 +11,13 @@ OpenLayers.Protocol = OpenLayers.Class({
/**
* Property: format
* {<OpenLayers.Format>}
* {<OpenLayers.Format>} The format used by this protocol.
*/
format: null,
/**
* Property: options
* Any options sent to the constructor.
* {Object} Any options sent to the constructor.
*/
options: null,

View File

@@ -19,14 +19,14 @@ OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
/**
* Property: url
* {String} - Service URL, read-only, set through the options
* {String} Service URL, read-only, set through the options
* passed to constructor.
*/
url: null,
/**
* Property: headers
* {Object} - HTTP request headers, read-only, set through the options
* {Object} HTTP request headers, read-only, set through the options
* passed to the constructor,
* Example: {'Content-Type': 'plain/text'}
*/
@@ -34,7 +34,7 @@ OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
/**
* Property: params
* {Object} - Parameters of GET requests, read-only, set through the options
* {Object} Parameters of GET requests, read-only, set through the options
* passed to the constructor,
* Example: {'bbox': '5,5,5,5'}
*/
@@ -42,7 +42,7 @@ OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
/**
* Property: callback
* {Object} - Function to be called when the <read>, <create>,
* {Object} Function to be called when the <read>, <create>,
* <update>, <delete> or <commit> operation completes, read-only,
* set through the options passed to the constructor.
*/
@@ -50,7 +50,7 @@ OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
/**
* Property: scope
* {Object} - Callback execution scope, read-only, set through the
* {Object} Callback execution scope, read-only, set through the
* options passed to the constructor.
*/
scope: null,
@@ -112,6 +112,15 @@ OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
* options - {Object} Optional object for configuring the request.
* This object is modified and should not be reused.
*
* Valid options:
* url - {String} Url for the request.
* params - {Object} Parameters to get serialized as a query string.
* headers - {Object} Headers to be set on the request.
* filter - {<OpenLayers.Filter.BBOX>} If a bbox filter is sent, it will be
* serialized according to the OpenSearch Geo extension
* (bbox=minx,miny,maxx,maxy). Note that a BBOX filter as the child
* of a logical filter will not be serialized.
*
* Returns:
* {<OpenLayers.Protocol.Response>} A response object, whose "priv" property
* references the HTTP request, this object is also passed to the
@@ -121,6 +130,14 @@ OpenLayers.Protocol.HTTP = OpenLayers.Class(OpenLayers.Protocol, {
read: function(options) {
options = OpenLayers.Util.applyDefaults(options, this.options);
var resp = new OpenLayers.Protocol.Response({requestType: "read"});
if(options.filter && options.filter instanceof OpenLayers.Filter.Spatial) {
if(options.filter.type == OpenLayers.Filter.Spatial.BBOX) {
options.params = OpenLayers.Util.extend(options.params, {
bbox: options.filter.value.toArray()
});
}
}
resp.priv = OpenLayers.Request.GET({
url: options.url,

View File

@@ -0,0 +1,87 @@
/* 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/Protocol.js
*/
/**
* Class: OpenLayers.Protocol.SQL
* Abstract SQL protocol class. Not to be instantiated directly. Use
* one of the SQL protocol subclasses instead.
*
* Inherits from:
* - <OpenLayers.Protocol>
*/
OpenLayers.Protocol.SQL = OpenLayers.Class(OpenLayers.Protocol, {
/**
* APIProperty: databaseName
* {String}
*/
databaseName: 'ol',
/**
* APIProperty: tableName
* Name of the database table into which Features should be saved.
*/
tableName: "ol_vector_features",
/**
* Property: postReadFiltering
* {Boolean} Whether the filter (if there's one) must be applied after
* the features have been read from the database; for example the
* BBOX strategy passes the read method a BBOX spatial filter, if
* postReadFiltering is true every feature read from the database
* will go through the BBOX spatial filter, which can be costly;
* defaults to true.
*/
postReadFiltering: true,
/**
* Constructor: OpenLayers.Protocol.SQL
*/
initialize: function(options) {
OpenLayers.Protocol.prototype.initialize.apply(this, [options]);
},
/**
* APIMethod: destroy
* Clean up the protocol.
*/
destroy: function() {
OpenLayers.Protocol.prototype.destroy.apply(this);
},
/**
* APIMethod: supported
* This should be overridden by specific subclasses
*
* Returns:
* {Boolean} Whether or not the browser supports the SQL backend
*/
supported: function() {
return false;
},
/**
* Method: evaluateFilter
* If postReadFiltering is true evaluate the filter against the feature
* and return the result of the evaluation, otherwise return true.
*
* Parameters:
* {<OpenLayers.Feature.Vector>} The feature.
* {<OpenLayers.Filter>} The filter.
*
* Returns:
* {Boolean} true if postReadFiltering if false, the result of the
* filter evaluation otherwise.
*/
evaluateFilter: function(feature, filter) {
return filter && this.postReadFiltering ?
filter.evaluate(feature) : true;
},
CLASS_NAME: "OpenLayers.Protocol.SQL"
});

View File

@@ -0,0 +1,559 @@
/* 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 Gears/gears_init.js
* @requires OpenLayers/Protocol/SQL.js
* @requires OpenLayers/Format/JSON.js
* @requires OpenLayers/Format/WKT.js
*/
/**
* Class: OpenLayers.Protocol.SQL.Gears
* This Protocol stores feature in the browser via the Gears Database module
* <http://code.google.com/apis/gears/api_database.html>.
*
* The main advantage is that all the read, create, update and delete operations
* can be done offline.
*
* Inherits from:
* - <OpenLayers.Protocol.SQL>
*/
OpenLayers.Protocol.SQL.Gears = OpenLayers.Class(OpenLayers.Protocol.SQL, {
/**
* Property: FID_PREFIX
* {String}
*/
FID_PREFIX: '__gears_fid__',
/**
* Property: NULL_GEOMETRY
* {String}
*/
NULL_GEOMETRY: '__gears_null_geometry__',
/**
* Property: NULL_FEATURE_STATE
* {String}
*/
NULL_FEATURE_STATE: '__gears_null_feature_state__',
/**
* Property: jsonParser
* {<OpenLayers.Format.JSON>}
*/
jsonParser: null,
/**
* Property: wktParser
* {<OpenLayers.Format.WKT>}
*/
wktParser: null,
/**
* Property: fidRegExp
* {RegExp} Regular expression to know whether a feature was
* created in offline mode.
*/
fidRegExp: null,
/**
* Property: saveFeatureState
* {Boolean} Whether to save the feature state (<OpenLayers.State>)
* into the database, defaults to true.
*/
saveFeatureState: true,
/**
* Property: typeOfFid
* {String} The type of the feature identifier, either "number" or
* "string", defaults to "string".
*/
typeOfFid: "string",
/**
* Property: db
* {GearsDatabase}
*/
db: null,
/**
* Constructor: OpenLayers.Protocol.SQL.Gears
*/
initialize: function(options) {
if (!this.supported()) {
return;
}
OpenLayers.Protocol.SQL.prototype.initialize.apply(this, [options]);
this.jsonParser = new OpenLayers.Format.JSON();
this.wktParser = new OpenLayers.Format.WKT();
this.fidRegExp = new RegExp('^' + this.FID_PREFIX);
this.initializeDatabase();
},
/**
* Method: initializeDatabase
*/
initializeDatabase: function() {
this.db = google.gears.factory.create('beta.database');
this.db.open(this.databaseName);
this.db.execute(
"CREATE TABLE IF NOT EXISTS " + this.tableName +
" (fid TEXT UNIQUE, geometry TEXT, properties TEXT," +
" state TEXT)");
},
/**
* APIMethod: destroy
* Clean up the protocol.
*/
destroy: function() {
this.db.close();
this.db = null;
this.jsonParser = null;
this.wktParser = null;
OpenLayers.Protocol.SQL.prototype.destroy.apply(this);
},
/**
* APIMethod: supported
* Determine whether a browser supports Gears
*
* Returns:
* {Boolean} The browser supports Gears
*/
supported: function() {
return !!(window.google && google.gears);
},
/**
* Method: read
* Read all features from the database and return a
* <OpenLayers.Protocol.Response> instance. If the options parameter
* contains a callback attribute, the function is called with the response
* as a parameter.
*
* Parameters:
* options - {Object} Optional object for configuring the request; it
* can have the {Boolean} property "noFeatureStateReset" which
* specifies if the state of features read from the Gears
* database must be reset to null, if "noFeatureStateReset"
* is undefined or false then each feature's state is reset
* to null, if "noFeatureStateReset" is true the feature state
* is preserved.
*
* Returns:
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
* object.
*/
read: function(options) {
options = OpenLayers.Util.applyDefaults(options, this.options);
var feature, features = [];
var rs = this.db.execute("SELECT * FROM " + this.tableName);
while (rs.isValidRow()) {
feature = this.unfreezeFeature(rs);
if (this.evaluateFilter(feature, options.filter)) {
if (!options.noFeatureStateReset) {
feature.state = null;
}
features.push(feature);
}
rs.next();
}
rs.close();
var resp = new OpenLayers.Protocol.Response({
code: OpenLayers.Protocol.Response.SUCCESS,
requestType: "read",
features: features
});
if (options && options.callback) {
options.callback.call(options.scope, resp);
}
return resp;
},
/**
* Method: unfreezeFeature
*
* Parameters:
* row - {ResultSet}
*
* Returns:
* {<OpenLayers.Feature.Vector>}
*/
unfreezeFeature: function(row) {
var feature;
var wkt = row.fieldByName('geometry');
if (wkt == this.NULL_GEOMETRY) {
feature = new OpenLayers.Feature.Vector();
} else {
feature = this.wktParser.read(wkt);
}
feature.attributes = this.jsonParser.read(
row.fieldByName('properties'));
feature.fid = this.extractFidFromField(row.fieldByName('fid'));
var state = row.fieldByName('state');
if (state == this.NULL_FEATURE_STATE) {
state = null;
}
feature.state = state;
return feature;
},
/**
* Method: extractFidFromField
*
* Parameters:
* field - {String}
*
* Returns
* {String} or {Number} The fid.
*/
extractFidFromField: function(field) {
if (!field.match(this.fidRegExp) && this.typeOfFid == "number") {
field = parseFloat(field);
}
return field;
},
/**
* Method: create
* Create new features into the database.
*
* Parameters:
* features - {Array({<OpenLayers.Feature.Vector>})} or
* {<OpenLayers.Feature.Vector>} The features to create in
* the database.
* options - {Object} Optional object for configuring the request.
*
* Returns:
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
* object.
*/
create: function(features, options) {
options = OpenLayers.Util.applyDefaults(options, this.options);
var resp = this.createOrUpdate(features);
resp.requestType = "create";
if (options && options.callback) {
options.callback.call(options.scope, resp);
}
return resp;
},
/**
* Method: update
* Construct a request updating modified feature.
*
* Parameters:
* features - {Array({<OpenLayers.Feature.Vector>})} or
* {<OpenLayers.Feature.Vector>} The features to update in
* the database.
* options - {Object} Optional object for configuring the request.
*
* Returns:
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
* object.
*/
update: function(features, options) {
options = OpenLayers.Util.applyDefaults(options, this.options);
var resp = this.createOrUpdate(features);
resp.requestType = "update";
if (options && options.callback) {
options.callback.call(options.scope, resp);
}
return resp;
},
/**
* Method: createOrUpdate
* Construct a request for updating or creating features in the
* database.
*
* Parameters:
* features - {Array({<OpenLayers.Feature.Vector>})} or
* {<OpenLayers.Feature.Vector>} The feature to create or update
* in the database.
*
* Returns:
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
* object.
*/
createOrUpdate: function(features) {
if (!(features instanceof Array)) {
features = [features];
}
var i, len = features.length, feature;
var insertedFeatures = new Array(len);
for (i = 0; i < len; i++) {
feature = features[i];
var params = this.freezeFeature(feature);
this.db.execute(
"REPLACE INTO " + this.tableName +
" (fid, geometry, properties, state)" +
" VALUES (?, ?, ?, ?)",
params);
var clone = feature.clone();
clone.fid = this.extractFidFromField(params[0]);
insertedFeatures[i] = clone;
}
return new OpenLayers.Protocol.Response({
code: OpenLayers.Protocol.Response.SUCCESS,
features: insertedFeatures,
reqFeatures: features
});
},
/**
* Method: freezeFeature
*
* Parameters:
* feature - {<OpenLayers.Feature.Vector>}
* state - {String} The feature state to store in the database.
*
* Returns:
* {Array}
*/
freezeFeature: function(feature) {
// 2 notes:
// - fid might not be a string
// - getFeatureStateForFreeze needs the feature fid to it's stored
// in the feature here
feature.fid = feature.fid != null ?
"" + feature.fid : OpenLayers.Util.createUniqueID(this.FID_PREFIX);
var geometry = feature.geometry != null ?
feature.geometry.toString() : this.NULL_GEOMETRY;
var properties = this.jsonParser.write(feature.attributes);
var state = this.getFeatureStateForFreeze(feature);
return [feature.fid, geometry, properties, state];
},
/**
* Method: getFeatureStateForFreeze
* Get the state of the feature to store into the database.
*
* Parameters:
* feature - {<OpenLayers.Feature.Vector>} The feature.
*
* Returns
* {String} The state
*/
getFeatureStateForFreeze: function(feature) {
var state;
if (!this.saveFeatureState) {
state = this.NULL_FEATURE_STATE;
} else if (this.createdOffline(feature)) {
// if the feature was created in offline mode, its
// state must remain INSERT
state = OpenLayers.State.INSERT;
} else {
state = feature.state;
}
return state;
},
/**
* Method: delete
* Delete features from the database.
*
* Parameters:
* features - {Array({<OpenLayers.Feature.Vector>})} or
* {<OpenLayers.Feature.Vector>}
* options - {Object} Optional object for configuring the request.
* This object is modified and should not be reused.
*
* Returns:
* {<OpenLayers.Protocol.Response>} An <OpenLayers.Protocol.Response>
* object.
*/
"delete": function(features, options) {
if (!(features instanceof Array)) {
features = [features];
}
options = OpenLayers.Util.applyDefaults(options, this.options);
var i, len, feature;
for (i = 0, len = features.length; i < len; i++) {
feature = features[i];
// if saveFeatureState is set to true and if the feature wasn't created
// in offline mode we don't delete it in the database but just update
// it state column
if (this.saveFeatureState && !this.createdOffline(feature)) {
var toDelete = feature.clone();
toDelete.fid = feature.fid;
if (toDelete.geometry) {
toDelete.geometry.destroy();
toDelete.geometry = null;
}
toDelete.state = feature.state;
this.createOrUpdate(toDelete);
} else {
this.db.execute(
"DELETE FROM " + this.tableName +
" WHERE fid = ?", [feature.fid]);
}
}
var resp = new OpenLayers.Protocol.Response({
code: OpenLayers.Protocol.Response.SUCCESS,
requestType: "delete",
reqFeatures: features
});
if (options && options.callback) {
options.callback.call(options.scope, resp);
}
return resp;
},
/**
* Method: createdOffline
* Returns true if the feature had a feature id when it was created in
* the Gears database, false otherwise; this is determined by
* checking the form of the feature's fid value.
*
* Parameters:
* feature - {<OpenLayers.Feature.Vector>}
*
* Returns:
* {Boolean}
*/
createdOffline: function(feature) {
return (typeof feature.fid == "string" &&
!!(feature.fid.match(this.fidRegExp)));
},
/**
* Method: commit
* Go over the features and for each take action
* based on the feature state. Possible actions are create,
* update and delete.
*
* Parameters:
* features - {Array({<OpenLayers.Feature.Vector>})}
* options - {Object} Object whose possible keys are "create", "update",
* "delete", "callback" and "scope", the values referenced by the
* first three are objects as passed to the "create", "update", and
* "delete" methods, the value referenced by the "callback" key is
* a function which is called when the commit operation is complete
* using the scope referenced by the "scope" key.
*
* Returns:
* {Array({<OpenLayers.Protocol.Response>})} An array of
* <OpenLayers.Protocol.Response> objects, one per request made
* to the database.
*/
commit: function(features, options) {
var opt, resp = [], nRequests = 0, nResponses = 0;
function callback(resp) {
if (++nResponses < nRequests) {
resp.last = false;
}
this.callUserCallback(options, resp);
}
var feature, toCreate = [], toUpdate = [], toDelete = [];
for (var i = features.length - 1; i >= 0; i--) {
feature = features[i];
switch (feature.state) {
case OpenLayers.State.INSERT:
toCreate.push(feature);
break;
case OpenLayers.State.UPDATE:
toUpdate.push(feature);
break;
case OpenLayers.State.DELETE:
toDelete.push(feature);
break;
}
}
if (toCreate.length > 0) {
nRequests++;
opt = OpenLayers.Util.applyDefaults(
{"callback": callback, "scope": this},
options.create
);
resp.push(this.create(toCreate, opt));
}
if (toUpdate.length > 0) {
nRequests++;
opt = OpenLayers.Util.applyDefaults(
{"callback": callback, "scope": this},
options.update
);
resp.push(this.update(toUpdate, opt));
}
if (toDelete.length > 0) {
nRequests++;
opt = OpenLayers.Util.applyDefaults(
{"callback": callback, "scope": this},
options["delete"]
);
resp.push(this["delete"](toDelete, opt));
}
return resp;
},
/**
* Method: clear
* Removes all rows of the table.
*/
clear: function() {
this.db.execute("DELETE FROM " + this.tableName);
},
/**
* Method: callUserCallback
* This method is called from within commit each time a request is made
* to the database, it is responsible for calling the user-supplied
* callbacks.
*
* Parameters:
* options - {Object} The map of options passed to the commit call.
* resp - {<OpenLayers.Protocol.Response>}
*/
callUserCallback: function(options, resp) {
var opt = options[resp.requestType];
if (opt && opt.callback) {
opt.callback.call(opt.scope, resp);
}
if (resp.last && options.callback) {
options.callback.call(options.scope);
}
},
CLASS_NAME: "OpenLayers.Protocol.SQL.Gears"
});

View File

@@ -810,7 +810,9 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
if (this.indexer) {
this.indexer.remove(element);
}
if (element._style.backgroundGraphic) {
var backgroundId = geometry.id + this.BACKGROUND_ID_SUFFIX;
var bElem = OpenLayers.Util.getElement(backgroundId);
if (bElem && bElem.parentNode) {

View File

@@ -153,7 +153,7 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* y - {Float}
*
* Returns:
* {Boolean} true if the translation parameters ar in the valid coordinates
* {Boolean} true if the translation parameters are in the valid coordinates
* range, false otherwise.
*/
translate: function(x, y) {
@@ -661,7 +661,7 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
// If so, add the coordinate of the intersection with the
// valid range bounds.
if (i > 0) {
if (this.getShortString(components[i + 1])) {
if (this.getShortString(components[i - 1])) {
strings.push(this.clipLine(components[i],
components[i-1]));
}

View File

@@ -33,6 +33,12 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
*/
symbolCache: {},
/**
* Property: offset
* {Object} Hash with "x" and "y" properties
*/
offset: null,
/**
* Constructor: OpenLayers.Renderer.VML
* Create a new VML renderer.
@@ -50,8 +56,10 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
style.addRule('olv\\:*', "behavior: url(#default#VML); " +
"position: absolute; display: inline-block;");
}
OpenLayers.Renderer.Elements.prototype.initialize.apply(this,
arguments);
this.offset = {x: 0, y: 0};
},
/**
@@ -90,8 +98,18 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
arguments);
var resolution = this.getResolution();
var org = extent.left/resolution + " " +
(extent.top/resolution - this.size.h);
var left = extent.left/resolution;
var top = extent.top/resolution - this.size.h;
if (resolutionChanged) {
this.offset = {x: left, y: top};
left = 0;
top = 0;
} else {
left = left - this.offset.x;
top = top - this.offset.y;
}
var org = left + " " + top;
this.root.setAttribute("coordorigin", org);
var size = this.size.w + " " + this.size.h;
@@ -191,8 +209,8 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
var yOffset = (style.graphicYOffset != undefined) ?
style.graphicYOffset : -(0.5 * height);
node.style.left = ((geometry.x/resolution)+xOffset).toFixed();
node.style.top = ((geometry.y/resolution)-(yOffset+height)).toFixed();
node.style.left = ((geometry.x/resolution - this.offset.x)+xOffset).toFixed();
node.style.top = ((geometry.y/resolution - this.offset.y)-(yOffset+height)).toFixed();
node.style.width = width + "px";
node.style.height = height + "px";
node.style.flip = "y";
@@ -339,7 +357,7 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
xOffset = xOffset * aspectRatio;
style.graphicWidth = size * aspectRatio;
style.graphicHeight = size;
this.graphicRotate(node, xOffset, yOffset)
this.graphicRotate(node, xOffset, yOffset);
}
}, this);
img.src = style.externalGraphic;
@@ -385,7 +403,7 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
var filter =
"progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta +
",M12=" + (-sintheta) + ",M21=" + sintheta + ",M22=" + costheta +
",SizingMethod='auto expand')\n"
",SizingMethod='auto expand')\n";
// set the opacity (needed for the imagedata)
var opacity = style.graphicOpacity || style.fillOpacity;
@@ -448,10 +466,10 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
var resolution = this.getResolution();
var scaledBox =
new OpenLayers.Bounds((bbox.left/resolution).toFixed(),
(bbox.bottom/resolution).toFixed(),
(bbox.right/resolution).toFixed(),
(bbox.top/resolution).toFixed());
new OpenLayers.Bounds((bbox.left/resolution - this.offset.x).toFixed(),
(bbox.bottom/resolution - this.offset.y).toFixed(),
(bbox.right/resolution - this.offset.x).toFixed(),
(bbox.top/resolution - this.offset.y).toFixed());
// Set the internal coordinate system to draw the path
node.style.left = scaledBox.left + "px";
@@ -493,7 +511,7 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
return (parts[0] == 1 || parts[1] == 1) ? "dot" : "dash";
} else if (parts.length == 4) {
return (1*parts[0] >= 2*parts[1]) ? "longdashdot" :
"dashdot"
"dashdot";
}
return "solid";
}
@@ -613,9 +631,9 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
drawCircle: function(node, geometry, radius) {
if(!isNaN(geometry.x)&& !isNaN(geometry.y)) {
var resolution = this.getResolution();
node.style.left = ((geometry.x /resolution).toFixed() - radius) + "px";
node.style.top = ((geometry.y /resolution).toFixed() - radius) + "px";
node.style.left = ((geometry.x /resolution - this.offset.x).toFixed() - radius) + "px";
node.style.top = ((geometry.y /resolution - this.offset.y).toFixed() - radius) + "px";
var diameter = radius * 2;
@@ -680,8 +698,8 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
var comp, x, y;
for (var i = 0; i < numComponents; i++) {
comp = geometry.components[i];
x = (comp.x/resolution);
y = (comp.y/resolution);
x = (comp.x/resolution - this.offset.x);
y = (comp.y/resolution - this.offset.y);
parts[i] = " " + x.toFixed() + "," + y.toFixed() + " l ";
}
var end = (closeLine) ? " x e" : " e";
@@ -713,8 +731,8 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
path.push("m");
for (i=0, ilen=linearRing.components.length; i<ilen; i++) {
comp = linearRing.components[i];
x = comp.x / resolution;
y = comp.y / resolution;
x = comp.x / resolution - this.offset.x;
y = comp.y / resolution - this.offset.y;
path.push(" " + x.toFixed() + "," + y.toFixed());
if (i==0) {
path.push(" l");
@@ -741,8 +759,8 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
drawRectangle: function(node, geometry) {
var resolution = this.getResolution();
node.style.left = geometry.x/resolution + "px";
node.style.top = geometry.y/resolution + "px";
node.style.left = (geometry.x/resolution - this.offset.x) + "px";
node.style.top = (geometry.y/resolution - this.offset.y) + "px";
node.style.width = geometry.width/resolution + "px";
node.style.height = geometry.height/resolution + "px";
@@ -769,8 +787,8 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
var comp, x, y;
for (var i=0, len=geometry.components.length; i<len; i++) {
comp = geometry.components[i];
x = comp.x / resolution;
y = comp.y / resolution;
x = comp.x / resolution - this.offset.x;
y = comp.y / resolution - this.offset.y;
if ((i%3)==0 && (i/3)==0) {
path.push("m");
} else if ((i%3)==1) {

View File

@@ -87,7 +87,11 @@ OpenLayers.Request = {
var request = new OpenLayers.Request.XMLHttpRequest();
var url = config.url;
if(config.params) {
url += "?" + OpenLayers.Util.getParameterString(config.params);
var paramString = OpenLayers.Util.getParameterString(config.params);
if(paramString.length > 0) {
var separator = (url.indexOf('?') > -1) ? '&' : '?';
url += separator + paramString;
}
}
if(config.proxy && (url.indexOf("http") == 0)) {
url = config.proxy + encodeURIComponent(url);
@@ -132,7 +136,7 @@ OpenLayers.Request = {
failure(request);
}
}
}
};
// send request (optionally with data) and return
request.send(config.data);
@@ -265,4 +269,4 @@ OpenLayers.Request = {
return OpenLayers.Request.issue(config);
}
};
};

View File

@@ -11,7 +11,7 @@ OpenLayers.Strategy = OpenLayers.Class({
/**
* Property: layer
* {<OpenLayers.Layer.Vector>}
* {<OpenLayers.Layer.Vector>} The layer this strategy belongs to.
*/
layer: null,
@@ -69,7 +69,8 @@ OpenLayers.Strategy = OpenLayers.Class({
},
/**
* Method: setLayer.
* Method: setLayer
* Called to set the <layer> property.
*
* Parameters:
* {<OpenLayers.Layer.Vector>}

View File

@@ -0,0 +1,210 @@
/* 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/Strategy.js
* @requires OpenLayers/Filter/Spatial.js
*/
/**
* Class: OpenLayers.Strategy.BBOX
* A simple strategy that reads new features when the viewport invalidates
* some bounds.
*
* Inherits from:
* - <OpenLayers.Strategy>
*/
OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, {
/**
* Property: bounds
* {<OpenLayers.Bounds>} The current data bounds.
*/
bounds: null,
/**
* Property: ratio
* {Float} The ratio of the data bounds to the viewport bounds (in each
* dimension).
*/
ratio: 2,
/**
* Property: response
* {<OpenLayers.Protocol.Response>} The protocol response object returned
* by the layer protocol.
*/
response: null,
/**
* Constructor: OpenLayers.Strategy.BBOX
* Create a new BBOX strategy.
*
* Parameters:
* options - {Object} Optional object whose properties will be set on the
* instance.
*/
initialize: function(options) {
OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
},
/**
* Method: activate
* Set up strategy with regard to reading new batches of remote data.
*
* Returns:
* {Boolean} The strategy was successfully activated.
*/
activate: function() {
var activated = OpenLayers.Strategy.prototype.activate.call(this);
if(activated) {
this.layer.events.on({
"moveend": this.update,
scope: this
});
this.layer.events.on({
"refresh": this.update,
scope: this
});
}
return activated;
},
/**
* Method: deactivate
* Tear down strategy with regard to reading new batches of remote data.
*
* Returns:
* {Boolean} The strategy was successfully deactivated.
*/
deactivate: function() {
var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
if(deactivated) {
this.layer.events.un({
"moveend": this.update,
scope: this
});
this.layer.events.un({
"refresh": this.update,
scope: this
});
}
return deactivated;
},
/**
* Method: update
* Callback function called on "moveend" or "refresh" layer events.
*
* Parameters:
* options - {Object} An object with a property named "force", this
* property references a boolean value indicating if new data
* must be incondtionally read.
*/
update: function(options) {
var mapBounds = this.layer.map.getExtent();
if ((options && options.force) || this.invalidBounds(mapBounds)) {
this.calculateBounds(mapBounds);
this.triggerRead();
}
},
/**
* Method: invalidBounds
*
* Parameters:
* mapBounds - {<OpenLayers.Bounds>} the current map extent, will be
* retrieved from the map object if not provided
*
* Returns:
* {Boolean}
*/
invalidBounds: function(mapBounds) {
if(!mapBounds) {
mapBounds = this.layer.map.getExtent();
}
return !this.bounds || !this.bounds.containsBounds(mapBounds);
},
/**
* Method: calculateBounds
*
* Parameters:
* mapBounds - {<OpenLayers.Bounds>} the current map extent, will be
* retrieved from the map object if not provided
*/
calculateBounds: function(mapBounds) {
if(!mapBounds) {
mapBounds = this.layer.map.getExtent();
}
var center = mapBounds.getCenterLonLat();
var dataWidth = mapBounds.getWidth() * this.ratio;
var dataHeight = mapBounds.getHeight() * this.ratio;
this.bounds = new OpenLayers.Bounds(
center.lon - (dataWidth / 2),
center.lat - (dataHeight / 2),
center.lon + (dataWidth / 2),
center.lat + (dataHeight / 2)
);
},
/**
* Method: triggerRead
*
* Returns:
* {<OpenLayers.Protocol.Response>} The protocol response object
* returned by the layer protocol.
*/
triggerRead: function() {
var filter = this.createFilter();
if (this.response && this.response.priv &&
typeof this.response.priv.abort == "function") {
this.response.priv.abort();
}
this.response = this.layer.protocol.read({
filter: filter,
callback: this.merge,
scope: this
});
},
/**
* Method: createFilter
*
* Returns
* {<OpenLayers.Filter>} The filter object.
*/
createFilter: function() {
var filter = new OpenLayers.Filter.Spatial({
type: OpenLayers.Filter.Spatial.BBOX,
value: this.bounds,
projection: this.layer.projection
});
if (this.layer.filter) {
filter = new OpenLayers.Filter.Logical({
type: OpenLayers.Filter.Logical.AND,
filters: [this.layer.filter, filter]
});
}
return filter;
},
/**
* Method: merge
* Given a list of features, determine which ones to add to the layer.
*
* Parameters:
* resp - {<OpenLayers.Protocol.Response>} The response object passed
* by the protocol.
*/
merge: function(resp) {
this.layer.destroyFeatures();
var features = resp.features;
if(features && features.length > 0) {
this.layer.addFeatures(features);
}
},
CLASS_NAME: "OpenLayers.Strategy.BBOX"
});

View File

@@ -0,0 +1,261 @@
/* 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/Strategy.js
*/
/**
* Class: OpenLayers.Strategy.Cluster
* Strategy for vector feature clustering.
*
* Inherits from:
* - <OpenLayers.Strategy>
*/
OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, {
/**
* Property: layer
* {<OpenLayers.Layer.Vector>} The layer that this strategy is assigned to.
*/
layer: null,
/**
* APIProperty: distance
* {Integer} Pixel distance between features that should be considered a
* single cluster. Default is 20 pixels.
*/
distance: 20,
/**
* Property: features
* {Array(<OpenLayers.Feature.Vector>)} Cached features.
*/
features: null,
/**
* Property: clusters
* {Array(<OpenLayers.Feature.Vector>)} Calculated clusters.
*/
clusters: null,
/**
* Property: clustering
* {Boolean} The strategy is currently clustering features.
*/
clustering: false,
/**
* Property: resolution
* {Float} The resolution (map units per pixel) of the current cluster set.
*/
resolution: null,
/**
* Constructor: OpenLayers.Strategy.Cluster
* Create a new clustering strategy.
*
* Parameters:
* options - {Object} Optional object whose properties will be set on the
* instance.
*/
initialize: function(options) {
OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
},
/**
* APIMethod: activate
* Activate the strategy. Register any listeners, do appropriate setup.
*
* Returns:
* {Boolean} The strategy was successfully activated.
*/
activate: function() {
var activated = OpenLayers.Strategy.prototype.activate.call(this);
if(activated) {
this.layer.events.on({
"beforefeaturesadded": this.cacheFeatures,
scope: this
});
this.layer.map.events.on({"zoomend": this.cluster, scope: this});
}
return activated;
},
/**
* APIMethod: deactivate
* Deactivate the strategy. Unregister any listeners, do appropriate
* tear-down.
*
* Returns:
* {Boolean} The strategy was successfully deactivated.
*/
deactivate: function() {
var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
if(deactivated) {
this.clearCache();
this.layer.events.un({
"beforefeaturesadded": this.cacheFeatures,
scope: this
});
this.layer.map.events.un({"zoomend": this.cluster, scope: this});
}
return deactivated;
},
/**
* Method: cacheFeatures
* Cache features before they are added to the layer.
*
* Parameters:
* event - {Object} The event that this was listening for. This will come
* with a batch of features to be clustered.
*
* Returns:
* {Boolean} False to stop layer from being added to the layer.
*/
cacheFeatures: function(event) {
var propagate = true;
if(!this.clustering) {
this.clearCache();
this.features = event.features;
this.cluster();
propagate = false;
}
return propagate;
},
/**
* Method: clearCache
* Clear out the cached features. This destroys features, assuming
* nothing else has a reference.
*/
clearCache: function() {
if(this.features) {
for(var i=0; i<this.features.length; ++i) {
this.features[i].destroy();
}
}
this.features = null;
},
/**
* Method: cluster
* Cluster features based on some threshold distance.
*/
cluster: function() {
if(this.features) {
var resolution = this.layer.getResolution();
if(resolution != this.resolution || !this.clustersExist()) {
this.resolution = resolution;
var clusters = [];
var feature, clustered, cluster;
for(var i=0; i<this.features.length; ++i) {
feature = this.features[i];
clustered = false;
for(var j=0; j<clusters.length; ++j) {
cluster = clusters[j];
if(this.shouldCluster(cluster, feature)) {
this.addToCluster(cluster, feature);
clustered = true;
break;
}
}
if(!clustered) {
clusters.push(this.createCluster(this.features[i]));
}
}
this.layer.destroyFeatures();
if(clusters.length > 0) {
this.clustering = true;
// A legitimate feature addition could occur during this
// addFeatures call. For clustering to behave well, features
// should be removed from a layer before requesting a new batch.
this.layer.addFeatures(clusters);
this.clustering = false;
}
this.clusters = clusters;
}
}
},
/**
* Method: clustersExist
* Determine whether calculated clusters are already on the layer.
*
* Returns:
* {Boolean} The calculated clusters are already on the layer.
*/
clustersExist: function() {
var exist = false;
if(this.clusters && this.clusters.length > 0 &&
this.clusters.length == this.layer.features.length) {
exist = true;
for(var i=0; i<this.clusters.length; ++i) {
if(this.clusters[i] != this.layer.features[i]) {
exist = false;
break;
}
}
}
return exist;
},
/**
* Method: shouldCluster
* Determine whether to include a feature in a given cluster.
*
* Parameters:
* cluster - {<OpenLayers.Feature.Vector>} A cluster.
* feature - {<OpenLayers.Feature.Vector>} A feature.
*
* Returns:
* {Boolean} The feature should be included in the cluster.
*/
shouldCluster: function(cluster, feature) {
var cc = cluster.geometry.getBounds().getCenterLonLat();
var fc = feature.geometry.getBounds().getCenterLonLat();
var distance = (
Math.sqrt(
Math.pow((cc.lon - fc.lon), 2) + Math.pow((cc.lat - fc.lat), 2)
) / this.resolution
);
return (distance <= this.distance);
},
/**
* Method: addToCluster
* Add a feature to a cluster.
*
* Parameters:
* cluster - {<OpenLayers.Feature.Vector>} A cluster.
* feature - {<OpenLayers.Feature.Vector>} A feature.
*/
addToCluster: function(cluster, feature) {
cluster.cluster.push(feature);
cluster.attributes.count += 1;
},
/**
* Method: createCluster
* Given a feature, create a cluster.
*
* Parameters:
* feature - {<OpenLayers.Feature.Vector>}
*
* Returns:
* {<OpenLayers.Feature.Vector>} A cluster.
*/
createCluster: function(feature) {
var center = feature.geometry.getBounds().getCenterLonLat();
var cluster = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(center.lon, center.lat),
{count: 1}
);
cluster.cluster = [feature];
return cluster;
},
CLASS_NAME: "OpenLayers.Strategy.Cluster"
});

View File

@@ -0,0 +1,241 @@
/* 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/Strategy.js
*/
/**
* Class: OpenLayers.Strategy.Paging
* Strategy for vector feature paging
*
* Inherits from:
* - <OpenLayers.Strategy>
*/
OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, {
/**
* Property: layer
* {<OpenLayers.Layer.Vector>} The layer that this strategy is assigned to.
*/
layer: null,
/**
* Property: features
* {Array(<OpenLayers.Feature.Vector>)} Cached features.
*/
features: null,
/**
* Property: length
* {Integer} Number of features per page. Default is 10.
*/
length: 10,
/**
* Property: num
* {Integer} The currently displayed page number.
*/
num: null,
/**
* Property: paging
* {Boolean} The strategy is currently changing pages.
*/
paging: false,
/**
* Constructor: OpenLayers.Strategy.Paging
* Create a new paging strategy.
*
* Parameters:
* options - {Object} Optional object whose properties will be set on the
* instance.
*/
initialize: function(options) {
OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
},
/**
* APIMethod: activate
* Activate the strategy. Register any listeners, do appropriate setup.
*
* Returns:
* {Boolean} The strategy was successfully activated.
*/
activate: function() {
var activated = OpenLayers.Strategy.prototype.activate.call(this);
if(activated) {
this.layer.events.on({
"beforefeaturesadded": this.cacheFeatures,
scope: this
});
}
return activated;
},
/**
* APIMethod: deactivate
* Deactivate the strategy. Unregister any listeners, do appropriate
* tear-down.
*
* Returns:
* {Boolean} The strategy was successfully deactivated.
*/
deactivate: function() {
var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
if(deactivated) {
this.clearCache();
this.layer.events.un({
"beforefeaturesadded": this.cacheFeatures,
scope: this
});
}
return deactivated;
},
/**
* Method: cacheFeatures
* Cache features before they are added to the layer.
*
* Parameters:
* event - {Object} The event that this was listening for. This will come
* with a batch of features to be paged.
*/
cacheFeatures: function(event) {
if(!this.paging) {
this.clearCache();
this.features = event.features;
this.pageNext(event);
}
},
/**
* Method: clearCache
* Clear out the cached features. This destroys features, assuming
* nothing else has a reference.
*/
clearCache: function() {
if(this.features) {
for(var i=0; i<this.features.length; ++i) {
this.features[i].destroy();
}
}
this.features = null;
this.num = null;
},
/**
* APIMethod: pageCount
* Get the total count of pages given the current cache of features.
*
* Returns:
* {Integer} The page count.
*/
pageCount: function() {
var numFeatures = this.features ? this.features.length : 0;
return Math.ceil(numFeatures / this.length);
},
/**
* APIMethod: pageNum
* Get the zero based page number.
*
* Returns:
* {Integer} The current page number being displayed.
*/
pageNum: function() {
return this.num;
},
/**
* APIMethod: pageLength
* Gets or sets page length.
*
* Parameters:
* newLength: {Integer} Optional length to be set.
*
* Returns:
* {Integer} The length of a page (number of features per page).
*/
pageLength: function(newLength) {
if(newLength && newLength > 0) {
this.length = newLength;
}
return this.length;
},
/**
* APIMethod: pageNext
* Display the next page of features.
*
* Returns:
* {Boolean} A new page was displayed.
*/
pageNext: function(event) {
var changed = false;
if(this.features) {
if(this.num === null) {
this.num = -1;
}
var start = (this.num + 1) * this.length;
changed = this.page(start, event);
}
return changed;
},
/**
* APIMethod: pagePrevious
* Display the previous page of features.
*
* Returns:
* {Boolean} A new page was displayed.
*/
pagePrevious: function() {
var changed = false;
if(this.features) {
if(this.num === null) {
this.num = this.pageCount();
}
var start = (this.num - 1) * this.length;
changed = this.page(start);
}
return changed;
},
/**
* Method: page
* Display the page starting at the given index from the cache.
*
* Returns:
* {Boolean} A new page was displayed.
*/
page: function(start, event) {
var changed = false;
if(this.features) {
if(start >= 0 && start < this.features.length) {
var num = Math.floor(start / this.length);
if(num != this.num) {
this.paging = true;
var features = this.features.slice(start, start + this.length);
this.layer.removeFeatures(this.layer.features);
this.num = num;
// modify the event if any
if(event && event.features) {
// this.was called by an event listener
event.features = features;
} else {
// this was called directly on the strategy
this.layer.addFeatures(features);
}
this.paging = false;
changed = true;
}
}
}
return changed;
},
CLASS_NAME: "OpenLayers.Strategy.Paging"
});

View File

@@ -373,11 +373,11 @@ OpenLayers.Util.onImageLoadError = function() {
break;
}
}
var guess = Math.floor(urls.length * Math.random())
var guess = Math.floor(urls.length * Math.random());
var new_url = urls[guess];
k = 0;
while(new_url == current_url && k++ < 4){
guess = Math.floor(urls.length * Math.random())
guess = Math.floor(urls.length * Math.random());
new_url = urls[guess];
}
this.src = src.replace(current_url, new_url);
@@ -796,13 +796,18 @@ OpenLayers.Util.rad = function(x) {return x*Math.PI/180;};
/**
* Function: distVincenty
* Given two objects representing points with geographic coordinates, this
* calculates the distance between those points on the surface of an
* ellipsoid.
*
* Parameters:
* p1 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
* p2 - {<OpenLayers.LonLat>} (or any object with both .lat, .lon properties)
*
* Returns:
* {Float}
* {Float} The distance (in km) between the two input points as measured on an
* ellipsoid. Note that the input point objects must be in geographic
* coordinates (decimal degrees) and the return distance is in kilometers.
*/
OpenLayers.Util.distVincenty=function(p1, p2) {
var a = 6378137, b = 6356752.3142, f = 1/298.257223563;
@@ -1397,7 +1402,7 @@ OpenLayers.Util.getRenderedDimensions = function(contentHTML, size, options) {
w = size.w;
container.style.width = w + "px";
} else if (size.h) {
h = size.h
h = size.h;
container.style.height = h + "px";
}
}

View File

@@ -4,7 +4,7 @@
<script type="text/javascript">
function test_Control_Navigation_constructor (t) {
t.plan( 2 );
t.plan( 3 );
var temp = OpenLayers.Control.prototype.initialize;
OpenLayers.Control.prototype.initialize = function() {
t.ok(true, "OpenLayers.Control's constructor called");
@@ -13,6 +13,8 @@
var control = new OpenLayers.Control.Navigation();
t.ok( control instanceof OpenLayers.Control.Navigation, "new OpenLayers.Control returns object" );
t.ok( !control.handleRightClicks, "'handleRightClicks' property is disabled by default");
OpenLayers.Control.prototype.initialize = temp;
}

View File

@@ -134,6 +134,99 @@
t.eq(this.map.controls[this.map.controls.length-1].CLASS_NAME, "CustomArgParser", "Custom ArgParser added correctly.");
t.eq(control.div.firstChild.getAttribute("href"), "./edit.html?zoom=2&lat=0&lon=1.75781&layers=B&customParam=foo", "Custom parameter encoded correctly.");
}
function test_Control_Permalink_createParams(t) {
t.plan(18);
var baseLayer = { 'isBaseLayer': true };
var m = {
'getCenter': function() { return null; }
};
var pl = {
'map': m,
'base': {}
};
old_getParameters = OpenLayers.Util.getParameters;
OpenLayers.Util.getParameters = function(base) {
t.ok(base == pl.base, "correct base sent in to Util.getParameters()");
return g_Params;
};
//null center, null map.getCenter()
g_Params = {};
m.baseLayer = baseLayer;
var returnParams = OpenLayers.Control.Permalink.prototype.createParams.apply(pl, []);
t.ok(returnParams == g_Params, "correct params returned on null center");
//valid center, zoom, layers
g_Params = { 'test': {} };
var center = { 'lon': 1.2345678901, 'lat': 9.8765432109 };
var zoom = {};
var layers = [
{ 'isBaseLayer': true },
baseLayer,
{ 'isBaseLayer': false, 'getVisibility': function() { return true; } },
{ 'isBaseLayer': false, 'getVisibility': function() { return false; } }
];
var returnParams = OpenLayers.Control.Permalink.prototype.createParams.apply(pl, [center, zoom, layers]);
t.ok(returnParams.test == g_Params.test, "correct params returned from Util.getParameters() when valid center, zoom, layers");
t.ok(returnParams.zoom == zoom, "params.zoom set correctly when valid center, zoom, layers");
t.eq(returnParams.lon, 1.23457, "lon set and rounded correctly when valid center, zoom, layers");
t.eq(returnParams.lat, 9.87654, "lat set and rounded correctly when valid center, zoom, layers");
t.eq(returnParams.layers, "0BTF", "layers processed correctly when valid center, zoom, layers")
//null center, zoom, layers, with displayProjection
g_Params = { 'test': {} };
g_Projection = {};
m = {
'baseLayer': baseLayer,
'getProjectionObject': function() { return g_Projection; },
'center': { 'lon': {}, 'lat': {} },
'getCenter': function() { return this.center; },
'zoom': {},
'getZoom': function() { return this.zoom; },
'layers': [
{ 'isBaseLayer': false, 'getVisibility': function() { return true; } },
baseLayer,
{ 'isBaseLayer': false, 'getVisibility': function() { return false; } },
{ 'isBaseLayer': true }
],
'getLayers': function() { return this.layers; }
};
pl = {
'base': {},
'map': m,
'displayProjection': {}
};
old_transform = OpenLayers.Projection.transform;
OpenLayers.Projection.transform = function(point, projObj, dispProj) {
t.ok(point.x = m.center.lon, "correct x value passed into transform");
t.ok(point.y = m.center.lat, "correct x value passed into transform");
t.ok(projObj == g_Projection, "correct projection object from map passed into transform");
t.ok(dispProj == pl.displayProjection, "correct displayProjection from control passed into transform");
return { 'x': 9.8765432109, 'y': 1.2345678901 };
};
center = zoom = layers = null;
var returnParams = OpenLayers.Control.Permalink.prototype.createParams.apply(pl, [center, zoom, layers]);
t.ok(returnParams.test == g_Params.test, "correct params returned from Util.getParameters() when null center, zoom, layers, with displayProjection");
t.ok(returnParams.zoom == m.zoom, "params.zoom set correctly when null center, zoom, layers, with displayProjection");
t.eq(returnParams.lon, 9.87654, "lon set, transformed, and rounded correctly when null center, zoom, layers, with displayProjection");
t.eq(returnParams.lat, 1.23457, "lat set, transformed, and rounded correctly when null center, zoom, layers, with displayProjection");
t.eq(returnParams.layers, "TBF0", "layers processed correctly when null center, zoom, layers, with displayProjection");
OpenLayers.Util.getParameters = old_getParameters;
OpenLayers.Projection.transform = old_transform;
}
</script>
</head>
<body>

View File

@@ -4,7 +4,7 @@
<script type="text/javascript">
function test_Format_constructor(t) {
t.plan(4);
t.plan(5);
var options = {'foo': 'bar'};
var format = new OpenLayers.Format(options);
@@ -13,6 +13,7 @@
t.eq(format.foo, "bar", "constructor sets options correctly");
t.eq(typeof format.read, "function", "format has a read function");
t.eq(typeof format.write, "function", "format has a write function");
t.eq(format.options, options, "format.options correctly set");
}
</script>

222
tests/Format/GML/cases.js Normal file
View File

@@ -0,0 +1,222 @@
var xml = new OpenLayers.Format.XML();
function readXML(file) {
return xml.read(document.getElementById(file).firstChild.nodeValue);
}
var cases = {
"v2/point-coord.xml": new OpenLayers.Geometry.Point(1, 2),
"v2/point-coordinates.xml": new OpenLayers.Geometry.Point(1, 2),
"v2/linestring-coord.xml": new OpenLayers.Geometry.LineString([
new OpenLayers.Geometry.Point(1, 2),
new OpenLayers.Geometry.Point(3, 4)
]),
"v2/linestring-coordinates.xml": new OpenLayers.Geometry.LineString([
new OpenLayers.Geometry.Point(1, 2),
new OpenLayers.Geometry.Point(3, 4)
]),
"v2/linearring-coord.xml": new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(1, 2),
new OpenLayers.Geometry.Point(3, 4),
new OpenLayers.Geometry.Point(5, 6),
new OpenLayers.Geometry.Point(1, 2)
]),
"v2/linearring-coordinates.xml": new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(1, 2),
new OpenLayers.Geometry.Point(3, 4),
new OpenLayers.Geometry.Point(5, 6),
new OpenLayers.Geometry.Point(1, 2)
]),
"v2/polygon-coord.xml": new OpenLayers.Geometry.Polygon([
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(1, 2),
new OpenLayers.Geometry.Point(3, 4),
new OpenLayers.Geometry.Point(5, 6),
new OpenLayers.Geometry.Point(1, 2)
]),
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(2, 3),
new OpenLayers.Geometry.Point(4, 5),
new OpenLayers.Geometry.Point(6, 7),
new OpenLayers.Geometry.Point(2, 3)
]),
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(3, 4),
new OpenLayers.Geometry.Point(5, 6),
new OpenLayers.Geometry.Point(7, 8),
new OpenLayers.Geometry.Point(3, 4)
])
]),
"v2/polygon-coordinates.xml": new OpenLayers.Geometry.Polygon([
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(1, 2),
new OpenLayers.Geometry.Point(3, 4),
new OpenLayers.Geometry.Point(5, 6),
new OpenLayers.Geometry.Point(1, 2)
]),
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(2, 3),
new OpenLayers.Geometry.Point(4, 5),
new OpenLayers.Geometry.Point(6, 7),
new OpenLayers.Geometry.Point(2, 3)
]),
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(3, 4),
new OpenLayers.Geometry.Point(5, 6),
new OpenLayers.Geometry.Point(7, 8),
new OpenLayers.Geometry.Point(3, 4)
])
]),
"v2/multipoint-coord.xml": new OpenLayers.Geometry.MultiPoint([
new OpenLayers.Geometry.Point(1, 2),
new OpenLayers.Geometry.Point(2, 3),
new OpenLayers.Geometry.Point(3, 4)
]),
"v2/multipoint-coordinates.xml": new OpenLayers.Geometry.MultiPoint([
new OpenLayers.Geometry.Point(1, 2),
new OpenLayers.Geometry.Point(2, 3),
new OpenLayers.Geometry.Point(3, 4)
]),
"v2/multilinestring-coord.xml": new OpenLayers.Geometry.MultiLineString([
new OpenLayers.Geometry.LineString([
new OpenLayers.Geometry.Point(1, 2),
new OpenLayers.Geometry.Point(2, 3)
]),
new OpenLayers.Geometry.LineString([
new OpenLayers.Geometry.Point(3, 4),
new OpenLayers.Geometry.Point(4, 5)
])
]),
"v2/multilinestring-coordinates.xml": new OpenLayers.Geometry.MultiLineString([
new OpenLayers.Geometry.LineString([
new OpenLayers.Geometry.Point(1, 2),
new OpenLayers.Geometry.Point(2, 3)
]),
new OpenLayers.Geometry.LineString([
new OpenLayers.Geometry.Point(3, 4),
new OpenLayers.Geometry.Point(4, 5)
])
]),
"v2/multipolygon-coord.xml": new OpenLayers.Geometry.MultiPolygon([
new OpenLayers.Geometry.Polygon([
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(1, 2),
new OpenLayers.Geometry.Point(3, 4),
new OpenLayers.Geometry.Point(5, 6),
new OpenLayers.Geometry.Point(1, 2)
]),
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(2, 3),
new OpenLayers.Geometry.Point(4, 5),
new OpenLayers.Geometry.Point(6, 7),
new OpenLayers.Geometry.Point(2, 3)
]),
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(3, 4),
new OpenLayers.Geometry.Point(5, 6),
new OpenLayers.Geometry.Point(7, 8),
new OpenLayers.Geometry.Point(3, 4)
])
]),
new OpenLayers.Geometry.Polygon([
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(1, 2),
new OpenLayers.Geometry.Point(3, 4),
new OpenLayers.Geometry.Point(5, 6),
new OpenLayers.Geometry.Point(1, 2)
])
])
]),
"v2/multipolygon-coordinates.xml": new OpenLayers.Geometry.MultiPolygon([
new OpenLayers.Geometry.Polygon([
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(1, 2),
new OpenLayers.Geometry.Point(3, 4),
new OpenLayers.Geometry.Point(5, 6),
new OpenLayers.Geometry.Point(1, 2)
]),
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(2, 3),
new OpenLayers.Geometry.Point(4, 5),
new OpenLayers.Geometry.Point(6, 7),
new OpenLayers.Geometry.Point(2, 3)
]),
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(3, 4),
new OpenLayers.Geometry.Point(5, 6),
new OpenLayers.Geometry.Point(7, 8),
new OpenLayers.Geometry.Point(3, 4)
])
]),
new OpenLayers.Geometry.Polygon([
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(1, 2),
new OpenLayers.Geometry.Point(3, 4),
new OpenLayers.Geometry.Point(5, 6),
new OpenLayers.Geometry.Point(1, 2)
])
])
]),
"v2/geometrycollection-coordinates.xml": new OpenLayers.Geometry.Collection([
new OpenLayers.Geometry.Point(1, 2),
new OpenLayers.Geometry.LineString([
new OpenLayers.Geometry.Point(1, 2),
new OpenLayers.Geometry.Point(3, 4)
]),
new OpenLayers.Geometry.Polygon([
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(1, 2),
new OpenLayers.Geometry.Point(3, 4),
new OpenLayers.Geometry.Point(5, 6),
new OpenLayers.Geometry.Point(1, 2)
]),
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(2, 3),
new OpenLayers.Geometry.Point(4, 5),
new OpenLayers.Geometry.Point(6, 7),
new OpenLayers.Geometry.Point(2, 3)
]),
new OpenLayers.Geometry.LinearRing([
new OpenLayers.Geometry.Point(3, 4),
new OpenLayers.Geometry.Point(5, 6),
new OpenLayers.Geometry.Point(7, 8),
new OpenLayers.Geometry.Point(3, 4)
])
])
]),
"v2/box-coord.xml": new OpenLayers.Bounds(1, 2, 3, 4),
"v2/box-coordinates.xml": new OpenLayers.Bounds(1, 2, 3, 4)
};
// cases for v3 use the same geometries
OpenLayers.Util.extend(cases, {
"v3/point.xml": cases["v2/point-coordinates.xml"],
"v3/linestring.xml": cases["v2/linestring-coordinates.xml"],
"v3/polygon.xml": cases["v2/polygon-coordinates.xml"],
"v3/multipoint-singular.xml": cases["v2/multipoint-coordinates.xml"],
"v3/multipoint-plural.xml": cases["v2/multipoint-coordinates.xml"],
"v3/multilinestring-singular.xml": cases["v2/multilinestring-coordinates.xml"],
"v3/multilinestring-plural.xml": cases["v2/multilinestring-coordinates.xml"],
"v3/multipolygon-singular.xml": cases["v2/multipolygon-coordinates.xml"],
"v3/multipolygon-plural.xml": cases["v2/multipolygon-coordinates.xml"],
"v3/multisurface-singular.xml": cases["v2/multipolygon-coordinates.xml"],
"v3/multisurface-plural.xml": cases["v2/multipolygon-coordinates.xml"],
"v3/envelope.xml": cases["v2/box-coordinates.xml"]
});

605
tests/Format/GML/v2.html Normal file

File diff suppressed because one or more lines are too long

551
tests/Format/GML/v3.html Normal file

File diff suppressed because one or more lines are too long

View File

@@ -27,7 +27,7 @@
'<' + '/ol:root>';
function test_Format_XML_constructor(t) {
t.plan(5);
t.plan(13);
var options = {'foo': 'bar'};
var format = new OpenLayers.Format.XML(options);
@@ -38,6 +38,36 @@
t.eq(typeof format.write, "function", "format has a write function");
t.ok(!window.ActiveXObject || format.xmldom, "browsers with activeX must have xmldom");
// test namespaces
t.ok(format.namespaces instanceof Object, "format has namespace object");
var namespaces = {"foo": "bar"};
format = new OpenLayers.Format.XML({namespaces: namespaces});
t.eq(format.namespaces, namespaces, "format.namespaces correctly set in constructor");
// test default prefix
t.eq(format.defaultPrefix, null, "defaultPrefix is null by default");
format = new OpenLayers.Format.XML({defaultPrefix: "foo"});
t.eq(format.defaultPrefix, "foo", "defaultPrefix correctly set in constructor");
// test readers
t.ok(format.readers instanceof Object, "format has readers object");
var readers = {"foo": "bar"};
format = new OpenLayers.Format.XML({readers: readers});
t.eq(format.readers, readers, "format.readers correctly set in constructor");
// test readers
t.ok(format.writers instanceof Object, "format has writers object");
var writers = {"foo": "bar"};
format = new OpenLayers.Format.XML({writers: writers});
t.eq(format.writers, writers, "format.writers correctly set in constructor");
}
function test_destroy(t) {
t.plan(1);
var format = new OpenLayers.Format.XML();
format.destroy();
t.eq(format.xmldom, null, "xmldom set to null for all browsers");
}
function test_Format_XML_read(t) {
@@ -260,6 +290,363 @@
found = format.hasAttributeNS(nodes[0], taUri, "nothing");
t.ok(found === false, "returns false for bad attribute");
}
function test_namespaces(t) {
t.plan(2);
var format = new OpenLayers.Format.XML({
namespaces: {
"def": "http://example.com/default",
"foo": "http://example.com/foo",
"bar": "http://example.com/bar"
},
defaultPrefix: "def"
});
// test that prototype has not been altered
t.eq(OpenLayers.Format.XML.prototype.namespaces, null,
"setting namespaces at construction does not modify prototype");
// test that namespaceAlias has been set
t.eq(format.namespaceAlias["http://example.com/foo"], "foo",
"namespaceAlias mapping has been set");
}
function test_setNamespace(t) {
t.plan(3);
var format = new OpenLayers.Format.XML();
// test that namespaces is an object
t.ok(format.namespaces instanceof Object, "empty namespace object set");
format.setNamespace("foo", "http://example.com/foo");
t.eq(format.namespaces["foo"], "http://example.com/foo", "alias -> uri mapping set");
t.eq(format.namespaceAlias["http://example.com/foo"], "foo", "uri -> alias mapping set");
}
function test_readChildNodes(t) {
var text = "<?xml version='1.0' encoding='UTF-8'?>" +
"<container xmlns='http://example.com/foo'>" +
"<marker name='my marker 1'>" +
"<position>" +
"<lon>-180</lon>" +
"<lat>90</lat>" +
"</position>" +
"<detail>some text for first marker</detail>" +
"<atom:link xmlns:atom='http://www.w3.org/2005/Atom' href='http://host/path/1'/>" +
"</marker>" +
"<marker name='my marker 2'>" +
"<position>" +
"<lon>180</lon>" +
"<lat>-90</lat>" +
"</position>" +
"<detail>some text for second marker</detail>" +
"<atom:link xmlns:atom='http://www.w3.org/2005/Atom' href='http://host/path/2'/>" +
"</marker>" +
"</container>";
var expect = [
new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(-180, 90),
{
name: 'my marker 1',
link: 'http://host/path/1',
detail: 'some text for first marker'
}
),
new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(180, -90),
{
name: 'my marker 2',
link: 'http://host/path/2',
detail: 'some text for second marker'
}
)
];
var format = new OpenLayers.Format.XML({
defaultPrefix: "foo",
namespaces: {
"foo": "http://example.com/foo",
"atom": "http://www.w3.org/2005/Atom"
},
readers: {
"foo": {
"container": function(node, obj) {
var list = [];
this.readChildNodes(node, list);
obj.list = list;
},
"marker": function(node, list) {
var feature = new OpenLayers.Feature.Vector();
feature.attributes.name = node.getAttribute("name");
this.readChildNodes(node, feature);
list.push(feature);
},
"position": function(node, feature) {
var obj = {};
this.readChildNodes(node, obj);
feature.geometry = new OpenLayers.Geometry.Point(obj.x, obj.y);
},
"lon": function(node, obj) {
obj.x = this.getChildValue(node);
},
"lat": function(node, obj) {
obj.y = this.getChildValue(node);
},
"detail": function(node, feature) {
feature.attributes.detail = this.getChildValue(node);
}
},
"atom": {
"link": function(node, feature) {
feature.attributes.link = node.getAttribute("href");
}
}
}
});
// convert text to document node
var doc = format.read(text);
// read child nodes to get back some object
var obj = format.readChildNodes(doc);
// start comparing what we got to what we expect
var got = obj.list;
t.plan(11);
t.eq(got.length, expect.length, "correct number of items parsed");
t.eq(got[0].geometry.x, expect[0].geometry.x, "correct x coord parsed for marker 1");
t.eq(got[0].geometry.y, expect[0].geometry.y, "correct y coord parsed for marker 1");
t.eq(got[0].attributes.name, expect[0].attributes.name, "correct name parsed for marker 1");
t.eq(got[0].attributes.detail, expect[0].attributes.detail, "correct detail parsed for marker 1");
t.eq(got[0].attributes.link, expect[0].attributes.link, "correct link parsed for marker 1");
t.eq(got[1].geometry.x, expect[1].geometry.x, "correct x coord parsed for marker 2");
t.eq(got[1].geometry.y, expect[1].geometry.y, "correct y coord parsed for marker 2");
t.eq(got[1].attributes.name, expect[1].attributes.name, "correct name parsed for marker 2");
t.eq(got[1].attributes.detail, expect[1].attributes.detail, "correct detail parsed for marker 2");
t.eq(got[1].attributes.link, expect[1].attributes.link, "correct link parsed for marker 2");
}
function test_writeNode(t) {
var features = [
new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(-180, 90),
{
name: 'my marker 1',
link: 'http://host/path/1',
detail: 'some text for first marker'
}
),
new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(180, -90),
{
name: 'my marker 2',
link: 'http://host/path/2',
detail: 'some text for second marker'
}
)
];
var expect = "<?xml version='1.0' encoding='UTF-8'?>" +
"<container xmlns='http://example.com/foo'>" +
"<marker name='my marker 1'>" +
"<position>" +
"<lon>-180</lon>" +
"<lat>90</lat>" +
"</position>" +
"<detail>some text for first marker</detail>" +
"<atom:link xmlns:atom='http://www.w3.org/2005/Atom' href='http://host/path/1'/>" +
"</marker>" +
"<marker name='my marker 2'>" +
"<position>" +
"<lon>180</lon>" +
"<lat>-90</lat>" +
"</position>" +
"<detail>some text for second marker</detail>" +
"<atom:link xmlns:atom='http://www.w3.org/2005/Atom' href='http://host/path/2'/>" +
"</marker>" +
"</container>";
var format = new OpenLayers.Format.XML({
defaultPrefix: "foo",
namespaces: {
"foo": "http://example.com/foo",
"atom": "http://www.w3.org/2005/Atom"
},
writers: {
"foo": {
"container": function(features) {
var node = this.createElementNSPlus("container");
var feature;
for(var i=0; i<features.length; ++i) {
feature = features[i];
this.writeNode("marker", features[i], node);
}
return node;
},
"marker": function(feature) {
var node = this.createElementNSPlus("marker", {
attributes: {name: feature.attributes.name}
});
this.writeNode("position", feature.geometry, node);
this.writeNode("detail", feature.attributes.detail, node);
this.writeNode("atom:link", feature.attributes.link, node);
return node;
},
"position": function(geometry) {
var node = this.createElementNSPlus("position");
this.writeNode("lon", geometry.x, node);
this.writeNode("lat", geometry.y, node);
return node;
},
"lon": function(x) {
return this.createElementNSPlus("lon", {
value: x
});
},
"lat": function(y) {
return this.createElementNSPlus("lat", {
value: y
});
},
"detail": function(text) {
return this.createElementNSPlus("detail", {
value: text
});
}
},
"atom": {
"link": function(href) {
return this.createElementNSPlus("atom:link", {
attributes: {href: href}
});
}
}
}
});
t.plan(1);
// test that we get what we expect from writeNode
var got = format.writeNode("container", features);
t.xml_eq(got, expect, "features correctly written");
}
function test_createElementNSPlus(t) {
var format = new OpenLayers.Format.XML({
defaultPrefix: "def",
namespaces: {
"def": "http://example.com/default",
"foo": "http://example.com/foo",
"bar": "http://example.com/bar"
}
});
var cases = [
{
description: "unprefixed name with default options",
node: format.createElementNSPlus("FooNode"),
expect: "<def:FooNode xmlns:def='http://example.com/default'/>"
}, {
description: "def prefixed name with default options",
node: format.createElementNSPlus("def:FooNode"),
expect: "<def:FooNode xmlns:def='http://example.com/default'/>"
}, {
description: "foo prefixed name with default options",
node: format.createElementNSPlus("foo:FooNode"),
expect: "<foo:FooNode xmlns:foo='http://example.com/foo'/>"
}, {
description: "unprefixed name with uri option",
node: format.createElementNSPlus("FooNode", {
uri: "http://example.com/elsewhere"
}),
expect: "<FooNode xmlns='http://example.com/elsewhere'/>"
}, {
description: "foo prefixed name with uri option (overriding format.namespaces)",
node: format.createElementNSPlus("foo:FooNode", {
uri: "http://example.com/elsewhere"
}),
expect: "<foo:FooNode xmlns:foo='http://example.com/elsewhere'/>"
}, {
description: "foo prefixed name with attributes option",
node: format.createElementNSPlus("foo:FooNode", {
attributes: {
"id": "123",
"foo:attr1": "namespaced attribute 1",
"bar:attr2": "namespaced attribute 2"
}
}),
expect: "<foo:FooNode xmlns:foo='http://example.com/foo' xmlns:bar='http://example.com/bar' id='123' foo:attr1='namespaced attribute 1' bar:attr2='namespaced attribute 2'/>"
}, {
description: "foo prefixed name with attributes and value options",
node: format.createElementNSPlus("foo:FooNode", {
attributes: {"id": "123"},
value: "text value"
}),
expect: "<foo:FooNode xmlns:foo='http://example.com/foo' id='123'>text value<" + "/foo:FooNode>"
}
];
t.plan(cases.length);
var test;
for(var i=0; i<cases.length; ++i) {
test = cases[i];
t.xml_eq(test.node, test.expect, test.description);
}
}
function test_setAttributes(t) {
var format = new OpenLayers.Format.XML({
defaultPrefix: "def",
namespaces: {
"def": "http://example.com/default",
"foo": "http://example.com/foo",
"bar": "http://example.com/bar"
}
});
var cases = [
{
description: "unprefixed attribute",
node: format.createElementNSPlus("foo:Node"),
attributes: {"id": "123"},
expect: "<foo:Node xmlns:foo='http://example.com/foo' id='123'/>"
}, {
description: "foo prefixed attribute",
node: format.createElementNSPlus("foo:Node"),
attributes: {"foo:id": "123"},
expect: "<foo:Node xmlns:foo='http://example.com/foo' foo:id='123'/>"
}, {
description: "foo prefixed attribute with def prefixed node",
node: format.createElementNSPlus("def:Node"),
attributes: {"foo:id": "123"},
expect: "<def:Node xmlns:def='http://example.com/default' xmlns:foo='http://example.com/foo' foo:id='123'/>"
}, {
description: "multiple attributes",
node: format.createElementNSPlus("def:Node"),
attributes: {"id": "123", "foo": "bar"},
expect: "<def:Node xmlns:def='http://example.com/default' id='123' foo='bar'/>"
}
];
t.plan(cases.length);
var test;
for(var i=0; i<cases.length; ++i) {
test = cases[i];
format.setAttributes(test.node, test.attributes);
t.xml_eq(test.node, test.expect, test.description);
}
}
</script>
</head>

View File

@@ -102,6 +102,35 @@
};
var resp = protocol.read(readOptions);
OpenLayers.Request.GET = _get;
}
function test_read_bbox(t) {
t.plan(1);
var protocol = new OpenLayers.Protocol.HTTP();
// fake XHR request object
var request = {'status': 200};
var _get = OpenLayers.Request.GET;
var bounds = new OpenLayers.Bounds(1, 2, 3, 4);
var filter = new OpenLayers.Filter.Spatial({
type: OpenLayers.Filter.Spatial.BBOX,
value: bounds,
projection: "foo"
});
OpenLayers.Request.GET = function(options) {
t.eq(options.params['bbox'].toString(), bounds.toArray().toString(),
'GET called with bbox filter in params');
return request;
};
var resp = protocol.read({filter: filter});
OpenLayers.Request.GET = _get;
}
function test_parseFeatures(t) {
@@ -217,6 +246,8 @@
};
var resp = protocol.create(features, createOptions);
OpenLayers.Request.POST = _post;
}
function test_update(t) {
@@ -284,8 +315,10 @@
};
var resp = protocol.update(feature, updateOptions);
OpenLayers.Request.PUT = _put;
}
function test_handleResponse(t) {
t.plan(6);
@@ -404,6 +437,7 @@
var resp = protocol['delete'](feature, deleteOptions);
OpenLayers.Request.DELETE = _delete;
}
function test_handleDelete(t) {

23
tests/Protocol/SQL.html Normal file
View File

@@ -0,0 +1,23 @@
<html>
<head>
<script src="../../lib/OpenLayers.js"></script>
<script type="text/javascript">
function test_initialize(t) {
t.plan(3);
var options = {tableName: 'my_features',
databaseName: 'my_database_name'}
var protocol = new OpenLayers.Protocol.SQL(options);
t.ok(protocol instanceof OpenLayers.Protocol.SQL,
"new OpenLayers.Protocol.SQL returns object");
t.eq(protocol.tableName, options.tableName, "tableName property is set");
t.eq(protocol.databaseName, options.databaseName, "databaseName property is set");
}
</script>
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1,473 @@
<html>
<head>
<script src="../../../lib/OpenLayers.js"></script>
<script type="text/javascript">
function test_initialize(t) {
var protocol = new OpenLayers.Protocol.SQL.Gears();
if (!protocol.supported()) {
t.plan(0);
return;
}
t.plan(5);
t.eq(protocol.CLASS_NAME, "OpenLayers.Protocol.SQL.Gears",
"ctor returns correct value");
t.eq(protocol.jsonParser.CLASS_NAME,
"OpenLayers.Format.JSON",
"ctor creates a JSON parser");
t.eq(protocol.wktParser.CLASS_NAME,
"OpenLayers.Format.WKT",
"ctor creates a WKT parser");
var str = protocol.FID_PREFIX + "foo_bar";
t.ok(str.match(protocol.fidRegExp),
"ctor creates correct regexp");
t.ok(typeof protocol.db == "object",
"ctor creates a db object");
protocol.clear();
protocol.destroy();
}
function test_destroy(t) {
var protocol = new OpenLayers.Protocol.SQL.Gears();
if (!protocol.supported()) {
t.plan(0);
return;
}
t.plan(3);
protocol.destroy();
t.eq(protocol.db, null,
"destroy nullifies db");
t.eq(protocol.jsonParser, null,
"destroy nullifies jsonParser");
t.eq(protocol.wktParser, null,
"destroy nullifies wktParser");
}
function test_read(t) {
var protocolCallback, readCallback;
var protocolOptions = {callback: protocolCallback};
var readOptions = {callback: readCallback};
var protocol = new OpenLayers.Protocol.SQL.Gears(protocolOptions);
if (!protocol.supported()) {
t.plan(0);
return;
}
function okCallback(resp) {
t.eq(resp.CLASS_NAME, "OpenLayers.Protocol.Response",
"read calls correct callback with a response object");
}
function failCallback(resp) {
t.fail("read calls incorrect callback");
}
t.plan(4);
var resp;
// 2 tests
protocolOptions.callback = okCallback;
readOptions.callback = failCallback;
resp = protocol.read();
t.eq(resp.CLASS_NAME, "OpenLayers.Protocol.Response",
"read returns a response object");
// 2 test
protocolOptions.callback = failCallback;
readOptions.callback = okCallback;
resp = protocol.read(readOptions);
t.eq(resp.CLASS_NAME, "OpenLayers.Protocol.Response",
"read returns a response object");
protocol.clear();
protocol.destroy();
}
function test_unfreezeFeature(t) {
var protocol = new OpenLayers.Protocol.SQL.Gears();
if (!protocol.supported()) {
t.plan(0);
return;
}
t.plan(10);
var feature;
var wkt, json, fid, state;
json = "{\"fake\":\"properties\"}";
fid = "1000";
state = OpenLayers.State.INSERT;
var row = {
fieldByName: function(str) {
if (str == "geometry") {
return wkt;
}
if (str == "properties") {
return json;
}
if (str == "fid") {
return fid;
}
if (str == "state") {
return state;
}
}
};
// 5 tests
wkt = "POINT(1 2)";
feature = protocol.unfreezeFeature(row);
t.eq(feature.CLASS_NAME, "OpenLayers.Feature.Vector",
"unfreezeFeature returns an OpenLayers.Feature.Vector");
t.ok(feature.geometry.x == 1 && feature.geometry.y == 2,
"unfreezeFeature returns a feature with correct geometry");
t.eq(feature.attributes.fake, "properties",
"unfreezeFeature returns a feature with correct attributes");
t.eq(feature.fid, fid,
"unfreezeFeature returns a feature with fid");
t.eq(feature.state, state,
"unfreezeFeature returns a feature with state");
// 5 tests
wkt = protocol.NULL_GEOMETRY;
state = protocol.NULL_FEATURE_STATE;
feature = protocol.unfreezeFeature(row);
t.eq(feature.CLASS_NAME, "OpenLayers.Feature.Vector",
"unfreezeFeature returns an OpenLayers.Feature.Vector");
t.eq(feature.geometry, null,
"unfreezeFeature returns a feature with correct geometry");
t.eq(feature.attributes.fake, "properties",
"unfreezeFeature returns a feature with correct attributes");
t.eq(feature.fid, fid,
"unfreezeFeature returns a feature with fid");
t.eq(feature.state, null,
"unfreezeFeature returns a feature with state");
protocol.clear();
protocol.destroy();
}
function test_extractFidFromField(t) {
var protocol = new OpenLayers.Protocol.SQL.Gears();
if (!protocol.supported()) {
t.plan(0);
return;
}
t.plan(4);
var field, fid;
// fid is a string, field is not prefixed with FID_PREFIX
// 1 test
field = "10";
res = protocol.extractFidFromField(field);
t.eq(res, "10",
"extractFidFromField returns expected string");
// fid is a string, field is prefixed with FID_PREFIX
// 1 test
field = protocol.FIX_PREFIX + "10";
res = protocol.extractFidFromField(field);
t.eq(res, protocol.FIX_PREFIX + "10",
"extractFidFromField returns expected prefixed string");
// fid is a number, field is not prefixed with FIX_PREFIX
// 1 test
protocol.typeOfFid = "number";
field = "10";
res = protocol.extractFidFromField(field);
t.eq(res, 10,
"extractFidFromField returns expected number");
// fid is a number, field is prefixed with FIX_PREFIX
// 1 test
protocol.typeOfFid = "number";
field = protocol.FID_PREFIX + "10";
res = protocol.extractFidFromField(field);
t.eq(res, protocol.FID_PREFIX + "10",
"extractFidFromField returns expected prefixed string");
}
function test_freezeFeature(t) {
var protocol = new OpenLayers.Protocol.SQL.Gears();
if (!protocol.supported()) {
t.plan(0);
return;
}
t.plan(8);
var feature, res;
// 4 tests
feature = new OpenLayers.Feature.Vector();
feature.geometry = new OpenLayers.Geometry.Point(1, 2);
feature.attributes.fake = "properties";
feature.fid = "1000";
feature.state = OpenLayers.State.INSERT;
res = protocol.freezeFeature(feature);
t.eq(res[0], feature.fid,
"freezeFeature returns correct fid");
t.eq(res[1], "POINT(1 2)",
"freezeFeature returns correct WKT");
t.eq(res[2], "{\"fake\":\"properties\"}",
"freezeFeature returns correct JSON");
t.eq(res[3], feature.state,
"freezeFeature returns correct feature state");
// 4 tests
protocol.saveFeatureState = false;
feature = new OpenLayers.Feature.Vector();
feature.attributes.fake = "properties";
feature.fid = "1000";
feature.state = OpenLayers.State.INSERT;
res = protocol.freezeFeature(feature);
t.eq(res[0], feature.fid,
"freezeFeature returns correct fid");
t.eq(res[1], protocol.NULL_GEOMETRY,
"freezeFeature returns expected null geom string");
t.eq(res[2], "{\"fake\":\"properties\"}",
"freezeFeature returns correct JSON");
t.eq(res[3], protocol.NULL_FEATURE_STATE,
"freezeFeature returns expected null feature state string");
protocol.clear();
protocol.destroy();
}
function test_create(t) {
var protocol = new OpenLayers.Protocol.SQL.Gears();
if (!protocol.supported()) {
t.plan(0);
return;
}
t.plan(8);
var resp;
var scope = {"fake": "scope"};
var options = {
callback: function(resp) {
t.eq(resp.CLASS_NAME, "OpenLayers.Protocol.Response",
"user callback is passed a response");
t.eq(resp.requestType, "create",
"user callback is passed correct request type in resp");
t.ok(this == scope,
"user callback called with correct scope");
},
scope: scope
};
// 4 tests
var feature = new OpenLayers.Feature.Vector();
feature.fid = "1000";
feature.attributes.fake = "properties";
feature.state = OpenLayers.State.INSERT;
resp = protocol.create([feature], options);
t.eq(resp.CLASS_NAME, "OpenLayers.Protocol.Response",
"create returns a response");
// check what we have in the DB
// 4 tests
resp = protocol.read({"noFeatureStateReset": true});
t.eq(resp.features.length, 1,
"create inserts feature in the DB");
t.eq(resp.features[0].fid, feature.fid,
"create inserts feature with correct fid");
t.eq(resp.features[0].attributes.fake, feature.attributes.fake,
"create inserts feature with correct attributes");
t.eq(resp.features[0].state, feature.state,
"create inserts feature with correct state");
protocol.clear();
protocol.destroy();
}
function test_createOrUpdate(t) {
var protocol = new OpenLayers.Protocol.SQL.Gears();
if (!protocol.supported()) {
t.plan(0);
return;
}
t.plan(5);
// 1 test
var feature = new OpenLayers.Feature.Vector();
feature.fid = "1000";
feature.attributes.fake = "properties";
feature.state = OpenLayers.State.INSERT;
resp = protocol.createOrUpdate([feature]);
t.eq(resp.CLASS_NAME, "OpenLayers.Protocol.Response",
"createOrUpdate returns a response");
// check what we have in the DB
// 4 tests
resp = protocol.read({"noFeatureStateReset": true});
t.eq(resp.features.length, 1,
"createOrUpdate inserts feature in the DB");
t.eq(resp.features[0].fid, feature.fid,
"createOrUpdate inserts feature with correct fid");
t.eq(resp.features[0].attributes.fake, feature.attributes.fake,
"createOrUpdate inserts feature with correct attributes");
t.eq(resp.features[0].state, feature.state,
"createOrUpdate inserts feature with correct state");
protocol.clear();
protocol.destroy();
}
function test_delete(t) {
var protocol = new OpenLayers.Protocol.SQL.Gears();
if (!protocol.supported()) {
t.plan(0);
return;
}
t.plan(4);
function createOneAndDeleteOne(fid, deleteOptions) {
var feature = new OpenLayers.Feature.Vector();
feature.fid = fid;
feature.attributes.fake = "properties";
feature.state = OpenLayers.State.INSERT;
var r = protocol.create([feature]);
protocol["delete"](r.reqFeatures, deleteOptions);
}
var resp, fid;
// 1 test
fid = 1000;
protocol.saveFeatureState = false;
createOneAndDeleteOne(fid)
resp = protocol.read();
t.eq(resp.features.length, 0,
"delete deletes feature if saveFeatureState is false");
protocol.clear();
// 1 test
fid = 1000;
protocol.saveFeatureState = true;
createOneAndDeleteOne(fid);
resp = protocol.read();
t.eq(resp.features.length, 1,
"delete does not delete feature if saveFeatureState is true");
protocol.clear();
// 1 test
fid = "1000";
protocol.saveFeatureState = true;
createOneAndDeleteOne(fid);
resp = protocol.read();
t.eq(resp.features.length, 1,
"delete does not delete feature if saveFeatureState is true");
protocol.clear();
// 1 test
fid = protocol.FID_PREFIX + "1000";
protocol.saveFeatureState = true;
createOneAndDeleteOne(fid, {dontDelete: true});
resp = protocol.read();
t.eq(resp.features.length, 0,
"delete deletes feature if saveFeatureState is true and fid is prefixed");
protocol.clear();
protocol.destroy();
}
function test_callUserCallback(t) {
var protocol = new OpenLayers.Protocol.SQL.Gears();
if (!protocol.supported()) {
t.plan(0);
return;
}
t.plan(6);
var options, resp;
var scope = {'fake': 'scope'};
// test commit callback
// 1 tests
options = {
'callback': function() {
t.ok(this == scope, 'callback called with correct scope');
},
'scope': scope
};
resp = {'requestType': 'create', 'last': true};
protocol.callUserCallback(options, resp);
// 0 test
resp = {'requestType': 'create', 'last': false};
protocol.callUserCallback(options, resp);
// test create callback
// 2 tests
options = {
'create': {
'callback': function(r) {
t.ok(this == scope, 'callback called with correct scope');
t.ok(r == resp, 'callback called with correct response');
},
'scope': scope
}
};
resp = {'requestType': 'create'};
protocol.callUserCallback(options, resp);
// test with both callbacks set
// 3 tests
options = {
'create': {
'callback': function(r) {
t.ok(this == scope, 'callback called with correct scope');
t.ok(r == resp, 'callback called with correct response');
},
'scope': scope
},
'callback': function() {
t.ok(this == scope, 'callback called with correct scope');
},
'scope': scope
};
resp = {'requestType': 'create', 'last': true};
protocol.callUserCallback(options, resp);
// no callback set
// 0 test
options = {
'delete': {
'callback': function(resp) {
t.fail('callback should not get called');
}
}
};
resp = {'requestType': 'create'};
protocol.callUserCallback(options, resp);
// cleanup
protocol.destroy();
}
</script>
</head>
<body>
</body>
</html>

View File

@@ -428,7 +428,8 @@
'removeChild': function(elem) {
gElemRemoved = elem;
}
}
},
'_style' : {backgroundGraphic: "foo"}
};
gBackElement = {
'parentNode': {

View File

@@ -437,7 +437,7 @@
return;
}
t.plan(1);
t.plan(3);
var r = new OpenLayers.Renderer.SVG(document.body);
r.setSize(new OpenLayers.Size(0, 0));
@@ -448,16 +448,29 @@
}
r.setExtent(new OpenLayers.Bounds(0, 0, 0, 0));
var node = document.createElement('div');
var geometry = new OpenLayers.Geometry.LineString([
new OpenLayers.Geometry.Point(0, -5000),
new OpenLayers.Geometry.Point(10000, 0),
new OpenLayers.Geometry.Point(0, 5000)
]);
var node = document.createElement('div');
r.drawLineString(node, geometry);
t.eq(node.getAttribute("points"), "0,10000,15000,2500,15000,-2500,0,-10000", "Geometry correctly clipped at inValidRange bounds");
t.eq(node.getAttribute("points"), "0,10000,15000,2500,15000,-2500,0,-10000", "Line with 3 points correctly clipped at inValidRange bounds");
geometry = new OpenLayers.Geometry.LineString([
new OpenLayers.Geometry.Point(0, -5000),
new OpenLayers.Geometry.Point(10000, 0)
]);
r.drawLineString(node, geometry);
t.eq(node.getAttribute("points"), "0,10000,15000,2500", "2-point line with 2nd point outside range correctly clipped at inValidRange bounds");
var geometry = new OpenLayers.Geometry.LineString([
new OpenLayers.Geometry.Point(10000, 0),
new OpenLayers.Geometry.Point(0, 5000)
]);
r.drawLineString(node, geometry);
t.eq(node.getAttribute("points"), "15000,-2500,0,-10000", "2-point line with 1st point outside range correctly clipped at inValidRange bounds");
}
</script>

View File

@@ -20,7 +20,7 @@
function test_issue(t) {
setup();
t.plan(19);
t.plan(22);
var request, config;
var proto = OpenLayers.Request.XMLHttpRequest.prototype;
var issue = OpenLayers.Function.bind(OpenLayers.Request.issue,
@@ -46,8 +46,43 @@
t.eq(async, config.async, "open called with correct async");
t.eq(user, config.user, "open called with correct user");
t.eq(password, config.password, "open called with correct password");
};
request = issue(config);
// test that params are serialized as query string - 1 test
config = {
method: "GET",
url: "http://example.com/",
params: {"foo": "bar"}
};
proto.open = function(method, url, async, user, password) {
t.eq(url, config.url + "?foo=bar", "params serialized as query string");
};
request = issue(config);
// test that empty params object doesn't produce query string - 1 test
config = {
method: "GET",
url: "http://example.com/",
params: {}
};
proto.open = function(method, url, async, user, password) {
t.eq(url, config.url, "empty params doesn't produce query string");
}
request = issue(config);
// test that query string doesn't get two ? separators
config = {
method: "GET",
url: "http://example.com/?existing=query",
params: {"foo": "bar"}
};
proto.open = function(method, url, async, user, password) {
t.eq(url, config.url + "&foo=bar", "existing query string gets extended with &");
}
request = issue(config);
// reset open method
proto.open = _open;
// test that headers are correctly set - 4 tests

166
tests/Strategy/BBOX.html Normal file
View File

@@ -0,0 +1,166 @@
<html>
<head>
<script src="../../lib/OpenLayers.js"></script>
<script type="text/javascript">
function test_initialize(t) {
t.plan(1);
var ratio = 4;
var s = new OpenLayers.Strategy.BBOX({ratio: ratio});
t.eq(s.ratio, ratio, "ctor sets ratio");
}
function test_activate(t) {
t.plan(5);
var l = new OpenLayers.Layer.Vector();
var s = new OpenLayers.Strategy.BBOX();
s.setLayer(l);
t.eq(s.active, false, "not active after construction");
var activated = s.activate();
t.eq(activated, true, "activate returns true");
t.eq(s.active, true, "activated after activate");
t.ok(l.events.listeners["moveend"][0].obj == s &&
l.events.listeners["moveend"][0].func == s.update,
"activates registers moveend listener");
t.ok(l.events.listeners["refresh"][0].obj == s &&
l.events.listeners["refresh"][0].func == s.update,
"activates registers refresh listener");
}
function test_update(t) {
t.plan(6);
var s = new OpenLayers.Strategy.BBOX();
var invalidBoundsReturnValue;
var bounds = new OpenLayers.Bounds(-100, -40, 100, 40);
s.invalidBounds = function(b) {
t.ok(b == bounds,
"update calls invalidBounds with correct arg");
return invalidBoundsReturnValue;
};
s.calculateBounds = function(b) {
t.ok(b == bounds,
"update calls calculateBounds with correct arg");
};
s.triggerRead = function() {
t.ok(true,
"update calls triggerRead");
};
s.setLayer({
map: {
getExtent: function() {
return bounds;
}
}
});
// 2 tests
invalidBoundsReturnValue = true;
s.update({force: true});
// 3 tests
invalidBoundsReturnValue = true;
s.update();
// 1 tests
invalidBoundsReturnValue = false;
s.update();
}
function test_triggerRead(t) {
t.plan(7);
var s = new OpenLayers.Strategy.BBOX();
var filter = {"fake": "filter"};
s.createFilter = function() {
return filter;
};
s.setLayer({
protocol: {
read: function(options) {
t.ok(options.filter == filter,
"protocol read called with correct filter");
t.ok(options.callback == s.merge,
"protocol read called with correct callback");
t.ok(options.scope == s,
"protocol read called with correct scope");
}
}
});
// 3 tests
s.triggerRead();
// 4 tests
s.response = {
priv: {
abort: function() {
t.ok(true,
"triggerRead aborts previous read request");
}
}
};
s.triggerRead();
}
function test_createFilter(t) {
t.plan(3);
var s = new OpenLayers.Strategy.BBOX();
var f;
// 2 test
s.setLayer({});
f = s.createFilter();
t.ok(f.CLASS_NAME.search(/^OpenLayers.Filter.Spatial/) != -1,
"createFilter returns a spatial filter object");
t.eq(f.type, OpenLayers.Filter.Spatial.BBOX,
"createFilter returns a BBOX-typed filter");
// 1 test
s.setLayer({filter: {fake: "filter"}});
f = s.createFilter();
t.ok(f.CLASS_NAME.search(/^OpenLayers.Filter.Logical/) != -1,
"createFilter returns a logical filter object");
}
function test_merge(t) {
t.plan(2);
var s = new OpenLayers.Strategy.BBOX();
var features = ["fake", "feature", "array"];
s.setLayer({
destroyFeatures: function() {
t.ok(true,
"merge calls destroyFeatures");
},
addFeatures: function(f) {
t.ok(f == features,
"merge calls addFeatures with the correct features");
}
});
// 2 tests
s.merge({features: features});
}
</script>
</head>
<body>
<div id="map" style="width: 400px; height: 200px" />
</body>
</html>

108
tests/Strategy/Cluster.html Normal file
View File

@@ -0,0 +1,108 @@
<html>
<head>
<script src="../../lib/OpenLayers.js"></script>
<script type="text/javascript">
function test_activate(t) {
t.plan(2);
var strategy = new OpenLayers.Strategy.Cluster();
t.eq(strategy.active, false, "not active after construction");
var layer = new OpenLayers.Layer.Vector("Vector Layer", {
strategies: [strategy]
});
var map = new OpenLayers.Map('map');
map.addLayer(layer);
t.eq(strategy.active, true, "active after adding to map");
}
function test_clusters(t) {
t.plan(10);
function featuresEq(got, exp) {
var eq = false;
if(got instanceof Array && exp instanceof Array) {
if(got.length === exp.length) {
for(var i=0; i<got.length; ++i) {
if(got[i] !== exp[i]) {
console.log(got[i], exp[i]);
break;
}
}
eq = (i == got.length);
}
}
return eq;
}
var strategy = new OpenLayers.Strategy.Cluster();
var layer = new OpenLayers.Layer.Vector("Vector Layer", {
strategies: [strategy],
isBaseLayer: true
});
var map = new OpenLayers.Map('map', {
resolutions: [4, 2, 1],
maxExtent: new OpenLayers.Bounds(-40, -40, 40, 40)
});
map.addLayer(layer);
// create features in a line, 1 unit apart
var features = new Array(80);
for(var i=0; i<80; ++i) {
features[i] = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(-40 + i, 0)
);
}
map.setCenter(new OpenLayers.LonLat(0, 0), 0);
layer.addFeatures(features);
// resolution 4
// threshold: 4 * 20 = 80 units
// one cluster
t.eq(layer.features.length, 1, "[4] layer has one cluster");
t.ok(featuresEq(layer.features[0].cluster, features), "[4] cluster includes all features");
// resolution 2
// threshold: 2 * 20 = 40 units
// two clusters (41 and 39) - first cluster includes all features within 40 units of the first (0-40 or 41 features)
map.zoomIn();
t.eq(layer.features.length, 2, "[2] layer has two clusters");
t.ok(featuresEq(layer.features[0].cluster, features.slice(0, 41)), "[2] first cluster includes first 41 features");
t.ok(featuresEq(layer.features[1].cluster, features.slice(41, 80)), "[2] second cluster includes last 39 features");
// resolution 1
// threshold: 1 * 20 = 20 units
// four clusters (21, 21, 21, and 17)
map.zoomIn();
t.eq(layer.features.length, 4, "[1] layer has four clusters");
t.ok(featuresEq(layer.features[0].cluster, features.slice(0, 21)), "[1] first cluster includes first 21 features");
t.ok(featuresEq(layer.features[1].cluster, features.slice(21, 42)), "[2] second cluster includes second 21 features");
t.ok(featuresEq(layer.features[2].cluster, features.slice(42, 63)), "[2] third cluster includes third 21 features");
t.ok(featuresEq(layer.features[3].cluster, features.slice(63, 80)), "[2] fourth cluster includes last 17 features");
}
function test_deactivate(t) {
t.plan(2);
var strategy = new OpenLayers.Strategy.Cluster();
var layer = new OpenLayers.Layer.Vector("Vector Layer", {
strategies: [strategy]
});
var map = new OpenLayers.Map('map');
map.addLayer(layer);
t.eq(strategy.active, true, "active after adding to map");
map.removeLayer(layer);
t.eq(strategy.active, false, "not active after removing from map");
}
</script>
</head>
<body>
<div id="map" style="width: 400px; height: 200px" />
</body>
</html>

113
tests/Strategy/Paging.html Normal file
View File

@@ -0,0 +1,113 @@
<html>
<head>
<script src="../../lib/OpenLayers.js"></script>
<script type="text/javascript">
function test_activate(t) {
t.plan(2);
var strategy = new OpenLayers.Strategy.Paging();
t.eq(strategy.active, false, "not active after construction");
var layer = new OpenLayers.Layer.Vector("Vector Layer", {
strategies: [strategy]
});
var map = new OpenLayers.Map('map');
map.addLayer(layer);
t.eq(strategy.active, true, "active after adding to map");
}
function test_paging(t) {
t.plan(18);
var strategy = new OpenLayers.Strategy.Paging();
var layer = new OpenLayers.Layer.Vector("Vector Layer", {
strategies: [strategy],
drawFeature: function() {}
});
var map = new OpenLayers.Map('map');
map.addLayer(layer);
var features = new Array(25);
for(var i=0; i<features.length; ++i) {
features[i] = {destroy: function() {}};
}
function featuresEq(got, exp) {
var eq = false;
if(got instanceof Array && exp instanceof Array) {
if(got.length === exp.length) {
for(var i=0; i<got.length; ++i) {
if(got[i] !== exp[i]) {
console.log(got[i], exp[i]);
break;
}
}
eq = (i == got.length);
}
}
return eq;
}
var len = strategy.pageLength();
t.eq(len, 10, "page length defaults to 10");
// add 25 features to the layer
layer.addFeatures(features);
t.eq(strategy.features.length, features.length, "strategy caches all features");
t.eq(layer.features.length, len, "layer gets one page of features");
t.ok(featuresEq(layer.features, features.slice(0, len)), "layer gets first page initially");
t.eq(strategy.pageNum(), 0, "strategy reports 0 based page number");
t.eq(strategy.pageCount(), Math.ceil(features.length / len), "strategy reports correct number of pages");
// load next page of features
var changed = strategy.pageNext();
t.eq(changed, true, "(1) strategy reports change");
t.eq(strategy.pageNum(), 1, "second page");
t.ok(featuresEq(layer.features, features.slice(len, 2*len)), "layer has second page of features");
// load next page of features (half page)
changed = strategy.pageNext();
t.eq(changed, true, "(2) strategy reports change");
t.eq(strategy.pageNum(), 2, "third page");
// try to change forward again
changed = strategy.pageNext();
t.eq(changed, false, "strategy reports no change");
t.eq(layer.features.length, features.length % len, "layer has partial page");
t.ok(featuresEq(layer.features, features.slice(2*len, 3*len)), "layer has third page of features");
t.eq(strategy.pageNum(), 2, "still on third page");
// change back a page
changed = strategy.pagePrevious();
t.eq(changed, true, "(3) strategy reports change");
t.eq(strategy.pageNum(), 1, "back on second page");
t.ok(featuresEq(layer.features, features.slice(len, 2*len)), "layer has second page of features again");
layer.destroy();
}
function test_deactivate(t) {
t.plan(2);
var strategy = new OpenLayers.Strategy.Paging();
var layer = new OpenLayers.Layer.Vector("Vector Layer", {
strategies: [strategy]
});
var map = new OpenLayers.Map('map');
map.addLayer(layer);
t.eq(strategy.active, true, "active after adding to map");
map.removeLayer(layer);
t.eq(strategy.active, false, "not active after removing from map");
}
</script>
</head>
<body>
<div id="map" style="width: 400px; height: 200px" />
</body>
</html>

110
tests/geom_eq.js Normal file
View File

@@ -0,0 +1,110 @@
/**
* File: xml_eq.js
* Adds a xml_eq method to AnotherWay test objects.
*
*/
(function() {
/**
* Function assertEqual
* Test two objects for equivalence (based on ==). Throw an exception
* if not equivalent.
*
* Parameters:
* got - {Object}
* expected - {Object}
* msg - {String} The message to be thrown. This message will be appended
* with ": got {got} but expected {expected}" where got and expected are
* replaced with string representations of the above arguments.
*/
function assertEqual(got, expected, msg) {
if(got === undefined) {
got = "undefined";
} else if (got === null) {
got = "null";
}
if(expected === undefined) {
expected = "undefined";
} else if (expected === null) {
expected = "null";
}
if(got != expected) {
throw msg + ": got '" + got + "' but expected '" + expected + "'";
}
}
/**
* Function assertGeometryEqual
* Test two geometries for equivalence. Geometries are considered
* equivalent if they are of the same class, and given component
* geometries, if all components are equivalent. Throws a message as
* exception if not equivalent.
*
* Parameters:
* got - {OpenLayers.Geometry}
* expected - {OpenLayers.Geometry}
* options - {Object} Optional object for configuring test options.
*/
function assertGeometryEqual(got, expected, options) {
var OpenLayers = Test.AnotherWay._g_test_iframe.OpenLayers;
// compare types
assertEqual(typeof got, typeof expected, "Object types mismatch");
// compare classes
assertEqual(got.CLASS_NAME, expected.CLASS_NAME, "Object class mismatch");
if(got instanceof OpenLayers.Geometry.Point) {
// compare points
assertEqual(got.x, expected.x, "x mismatch");
assertEqual(got.y, expected.y, "y mismatch");
assertEqual(got.z, expected.z, "z mismatch");
} else {
// compare components
assertEqual(
got.components.length, expected.components.length,
"Component length mismatch for " + got.CLASS_NAME
);
for(var i=0; i<got.components.length; ++i) {
try {
assertGeometryEqual(
got.components[i], expected.components[i], options
);
} catch(err) {
throw "Bad component " + i + " for " + got.CLASS_NAME + ": " + err;
}
}
}
return true;
}
/**
* Function: Test.AnotherWay._test_object_t.geom_eq
* Test if two geometry objects are equivalent. Tests for same geometry
* class, same number of components (if any), equivalent component
* geometries, and same coordinates.
*
* (code)
* t.geom_eq(got, expected, message);
* (end)
*
* Parameters:
* got - {OpenLayers.Geometry} Any geometry instance.
* expected - {OpenLayers.Geometry} The expected geometry.
* msg - {String} A message to print with test output.
* options - {Object} Optional object for configuring test options.
*/
var proto = Test.AnotherWay._test_object_t.prototype;
proto.geom_eq = function(got, expected, msg, options) {
// test geometries for equivalence
try {
assertGeometryEqual(got, expected, options);
this.ok(true, msg);
} catch(err) {
this.fail(msg + ": " + err);
}
}
})();

View File

@@ -43,6 +43,8 @@
<li>Format/GeoJSON.html</li>
<li>Format/GeoRSS.html</li>
<li>Format/GML.html</li>
<li>Format/GML/v2.html</li>
<li>Format/GML/v3.html</li>
<li>Format/GPX.html</li>
<li>Format/JSON.html</li>
<li>Format/KML.html</li>
@@ -115,6 +117,8 @@
<li>Projection.html</li>
<li>Protocol.html</li>
<li>Protocol/HTTP.html</li>
<li>Protocol/SQL.html</li>
<li>Protocol/SQL/Gears.html</li>
<li>Renderer.html</li>
<li>Renderer/Canvas.html</li>
<li>Renderer/Elements.html</li>
@@ -124,7 +128,10 @@
<li>Request/XMLHttpRequest.html</li>
<li>Rule.html</li>
<li>Strategy.html</li>
<li>Strategy/Cluster.html</li>
<li>Strategy/Fixed.html</li>
<li>Strategy/Paging.html</li>
<li>Strategy/BBOX.html</li>
<li>Style.html</li>
<li>StyleMap.html</li>
<li>Tile.html</li>

View File

@@ -2307,6 +2307,7 @@ onload=function()
// -->
</script>
<script type="text/javascript" src="xml_eq.js"></script>
<script type="text/javascript" src="geom_eq.js"></script>
</head><body>
<div id="col1">

View File

@@ -97,10 +97,13 @@
* Parameters:
* got - {DOMElement}
* expected - {DOMElement}
* options - {Object} Optional object for configuring test options. Set
* 'prefix' property to true in order to compare element and attribute
* prefixes (namespace uri always tested). By default, prefixes
* are not tested.
* options - {Object} Optional object for configuring test options.
*
* Valid options:
* prefix - {Boolean} Compare element and attribute
* prefixes (namespace uri always tested). Default is false.
* includeWhiteSpace - {Boolean} Include whitespace only nodes when
* comparing child nodes. Default is false.
*/
function assertElementNodesEqual(got, expected, options) {
var testPrefix = (options && options.prefix === true);
@@ -190,14 +193,17 @@
}
// compare children
var gotChildNodes = getChildNodes(got, options);
var expChildNodes = getChildNodes(expected, options);
assertEqual(
got.childNodes.length, expected.childNodes.length,
gotChildNodes.length, expChildNodes.length,
"Children length mismatch for " + got.nodeName
);
for(var j=0; j<got.childNodes.length; ++j) {
for(var j=0; j<gotChildNodes.length; ++j) {
try {
assertElementNodesEqual(
got.childNodes[j], expected.childNodes[j]
gotChildNodes[j], expChildNodes[j], options
);
} catch(err) {
throw "Bad child " + j + " for element " + got.nodeName + ": " + err;
@@ -206,6 +212,50 @@
}
return true;
}
/**
* Function getChildNodes
* Returns the child nodes of the specified nodes. By default this method
* will ignore child text nodes which are made up of whitespace content.
* The 'includeWhiteSpace' option is used to control this behaviour.
*
* Parameters:
* node - {DOMElement}
* options - {Object} Optional object for test configuration.
*
* Valid options:
* includeWhiteSpace - {Boolean} Include whitespace only nodes when
* comparing child nodes. Default is false.
*
* Returns:
* {Array} of {DOMElement}
*/
function getChildNodes(node, options) {
//check whitespace
if (options && options.includeWhiteSpace) {
return node.childNodes;
}
else {
nodes = [];
for (var i = 0; i < node.childNodes.length; i++ ) {
var child = node.childNodes[i];
if (child.nodeType == 1) {
//element node, add it
nodes.push(child);
}
else if (child.nodeType == 3) {
//text node, add if non empty
if (child.nodeValue &&
child.nodeValue.replace(/^\s*(.*?)\s*$/, "$1") != "" ) {
nodes.push(child);
}
}
}
return nodes;
}
}
/**
* Function: Test.AnotherWay._test_object_t.xml_eq
@@ -221,10 +271,13 @@
* got - {DOMElement | String} A DOM node or XML string to test.
* expected - {DOMElement | String} The expected DOM node or XML string.
* msg - {String} A message to print with test output.
* options - {Object} Optional object for configuring test options. Set
* 'prefix' property to true in order to compare element and attribute
* prefixes (namespace uri always tested). By default, prefixes
* are not tested.
* options - {Object} Optional object for configuring test.
*
* Valid options:
* prefix - {Boolean} Compare element and attribute
* prefixes (namespace uri always tested). Default is false.
* includeWhiteSpace - {Boolean} Include whitespace only nodes when
* comparing child nodes. Default is false.
*/
var proto = Test.AnotherWay._test_object_t.prototype;
proto.xml_eq = function(got, expected, msg, options) {
@@ -255,4 +308,4 @@
}
}
})();
})();