From dc93478e6bcc0e827bbfdb7663e743fef6cfdba7 Mon Sep 17 00:00:00 2001 From: Matt Priour Date: Wed, 8 Aug 2012 22:34:26 -0500 Subject: [PATCH 001/123] Move zeroPad function to BaseTypes and add tests for it --- lib/OpenLayers/BaseTypes.js | 20 +++++++++++++++++++- tests/BaseTypes.html | 11 +++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/OpenLayers/BaseTypes.js b/lib/OpenLayers/BaseTypes.js index b0c96956a7..87617da3c5 100644 --- a/lib/OpenLayers/BaseTypes.js +++ b/lib/OpenLayers/BaseTypes.js @@ -295,7 +295,25 @@ OpenLayers.Number = { str = integer + dsep + rem; } return str; - } + }, + + /** + * Method: zeroPad + * Create a zero padded string optionally with a radix for casting numbers. + * + * Parameters: + * num - {Number} The number to be zero padded. + * len - {Number} The length of the string to be returned. + * radix - {Number} An integer between 2 and 36 specifying the base to use + * for representing numeric values. + */ + zeroPad: function(num, len, radix) { + var str = num.toString(radix || 10); + while (str.length < len) { + str = "0" + str; + } + return str; + } }; /** diff --git a/tests/BaseTypes.html b/tests/BaseTypes.html index cc391003da..045ac65491 100644 --- a/tests/BaseTypes.html +++ b/tests/BaseTypes.html @@ -278,6 +278,17 @@ OpenLayers.Number.decimalSeparator = ","; t.eq(format(num, 3), "12.345,679", "changing thousands/decimal separator globally works"); } + + function test_Number_zeroPad(t) { + t.plan(6); + var pad = OpenLayers.Number.zeroPad; + t.eq(pad(15, 4), "0015", "left padding works"); + t.eq(pad(15, 2), "15", "no left padding when equal to number of digits"); + t.eq(pad(15, 1), "15", "no left padding when less than number of digits"); + t.eq(pad(10, 5, 2), "01010", "radix modified and padding works"); + t.eq(pad(10, 5, 8), "00012", "radix modified and padding works"); + t.eq(pad(10, 5, 36), "0000a", "radix modified and padding works"); + } function test_Function_bind(t) { t.plan(12); From a83ab56f97f0e73fbea7b4cf08937b90f6443af8 Mon Sep 17 00:00:00 2001 From: Matt Priour Date: Wed, 8 Aug 2012 22:36:39 -0500 Subject: [PATCH 002/123] Modify classes which contained an internal numeric zero padding function to use the one in BaseTypes instead --- lib/OpenLayers/BaseTypes/Date.js | 19 ++++++------------ lib/OpenLayers/Layer/ArcGISCache.js | 24 +++------------------- lib/OpenLayers/Layer/TileCache.js | 31 ++++++++--------------------- 3 files changed, 17 insertions(+), 57 deletions(-) diff --git a/lib/OpenLayers/BaseTypes/Date.js b/lib/OpenLayers/BaseTypes/Date.js index 937b12d108..e7da56eb6f 100644 --- a/lib/OpenLayers/BaseTypes/Date.js +++ b/lib/OpenLayers/BaseTypes/Date.js @@ -49,13 +49,6 @@ OpenLayers.Date = { return date.toISOString(); }; } else { - function pad(num, len) { - var str = num + ""; - while (str.length < len) { - str = "0" + str; - } - return str; - } return function(date) { var str; if (isNaN(date.getTime())) { @@ -65,12 +58,12 @@ OpenLayers.Date = { } else { str = date.getUTCFullYear() + "-" + - pad(date.getUTCMonth() + 1, 2) + "-" + - pad(date.getUTCDate(), 2) + "T" + - pad(date.getUTCHours(), 2) + ":" + - pad(date.getUTCMinutes(), 2) + ":" + - pad(date.getUTCSeconds(), 2) + "." + - pad(date.getUTCMilliseconds(), 3) + "Z"; + OpenLayers.Number.zeroPad(date.getUTCMonth() + 1, 2) + "-" + + OpenLayers.Number.zeroPad(date.getUTCDate(), 2) + "T" + + OpenLayers.Number.zeroPad(date.getUTCHours(), 2) + ":" + + OpenLayers.Number.zeroPad(date.getUTCMinutes(), 2) + ":" + + OpenLayers.Number.zeroPad(date.getUTCSeconds(), 2) + "." + + OpenLayers.Number.zeroPad(date.getUTCMilliseconds(), 3) + "Z"; } return str; }; diff --git a/lib/OpenLayers/Layer/ArcGISCache.js b/lib/OpenLayers/Layer/ArcGISCache.js index 27173392c4..8c27c41431 100644 --- a/lib/OpenLayers/Layer/ArcGISCache.js +++ b/lib/OpenLayers/Layer/ArcGISCache.js @@ -443,9 +443,9 @@ OpenLayers.Layer.ArcGISCache = OpenLayers.Class(OpenLayers.Layer.XYZ, { url = url + '/tile/${z}/${y}/${x}'; } else { // The tile images are stored using hex values on disk. - x = 'C' + this.zeroPad(x, 8, 16); - y = 'R' + this.zeroPad(y, 8, 16); - z = 'L' + this.zeroPad(z, 2, 16); + x = 'C' + OpenLayers.Number.zeroPad(x, 8, 16); + y = 'R' + OpenLayers.Number.zeroPad(y, 8, 16); + z = 'L' + OpenLayers.Number.zeroPad(z, 2, 16); url = url + '/${z}/${y}/${x}.' + this.type; } @@ -457,23 +457,5 @@ OpenLayers.Layer.ArcGISCache = OpenLayers.Class(OpenLayers.Layer.XYZ, { ); }, - /** - * Method: zeroPad - * Create a zero padded string optionally with a radix for casting numbers. - * - * Parameters: - * num - {Number} The number to be zero padded. - * len - {Number} The length of the string to be returned. - * radix - {Number} An integer between 2 and 36 specifying the base to use - * for representing numeric values. - */ - zeroPad: function(num, len, radix) { - var str = num.toString(radix || 10); - while (str.length < len) { - str = "0" + str; - } - return str; - }, - CLASS_NAME: 'OpenLayers.Layer.ArcGISCache' }); diff --git a/lib/OpenLayers/Layer/TileCache.js b/lib/OpenLayers/Layer/TileCache.js index e4e92e9766..3008979c1f 100644 --- a/lib/OpenLayers/Layer/TileCache.js +++ b/lib/OpenLayers/Layer/TileCache.js @@ -116,31 +116,16 @@ OpenLayers.Layer.TileCache = OpenLayers.Class(OpenLayers.Layer.Grid, { var tileZ = this.serverResolutions != null ? OpenLayers.Util.indexOf(this.serverResolutions, res) : this.map.getZoom(); - /** - * Zero-pad a positive integer. - * number - {Int} - * length - {Int} - * - * Returns: - * {String} A zero-padded string - */ - function zeroPad(number, length) { - number = String(number); - var zeros = []; - for(var i=0; i Date: Tue, 18 Sep 2012 08:14:54 +0200 Subject: [PATCH 003/123] [New] raise feature function to move features in layer. --- lib/OpenLayers/Layer/Vector.js | 23 +++++++++++++- tests/Layer/Vector.html | 56 +++++++++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/lib/OpenLayers/Layer/Vector.js b/lib/OpenLayers/Layer/Vector.js index 4300e59b16..ddd2f6f4a0 100644 --- a/lib/OpenLayers/Layer/Vector.js +++ b/lib/OpenLayers/Layer/Vector.js @@ -699,7 +699,28 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, { this.events.triggerEvent("featuresremoved", {features: features}); } }, - + + /** + * APIMethod: raiseFeature + * Changes the index of the given feature by delta and redraws the layer. If delta is positive, the feature is moved up the layer's feature stack; if delta is negative, the feature is moved down. + * If delta + current is negative it is set to 0 and feature will be at the bottom; if it is bigger then the features count than it is set to the last index and the feature will be at the top. + */ + raiseFeature:function(feature, delta) { + var base = this.features.indexOf(feature); + var idx = base + delta; + if (idx < 0) { + idx = 0; + } else if (idx > this.features.length) { + idx = this.features.length; + } + if (base != idx) { + this.features.splice(base, 1); + this.features.splice(idx, 0, feature); + this.eraseFeatures(this.features); + this.redraw(); + } + }, + /** * APIMethod: removeAllFeatures * Remove all features from the layer. diff --git a/tests/Layer/Vector.html b/tests/Layer/Vector.html index aa3e2f8a7e..2cfc9c07bd 100644 --- a/tests/Layer/Vector.html +++ b/tests/Layer/Vector.html @@ -461,7 +461,44 @@ layer.features = []; } - + function test_drawfeature_ng(t) { + t.plan(3); + var layer = new OpenLayers.Layer.Vector(); + layer.drawn = true; + var log = []; + + // Bogus layer renderer needs some methods + // for functional tests. + var renderer = { + initialize: function() {}, + drawFeature: function(feature, style) { + log.push(style); + }, + root: document.createElement("div"), + destroy: function() { }, + eraseFeatures: function() {}, + setExtent: function() {}, + setSize: function() {} + }; + var OrigRendererNG = OpenLayers.Renderer.NG; + OpenLayers.Renderer.NG = OpenLayers.Class(renderer); + + layer.renderer = new OpenLayers.Renderer.NG(); + layer.drawFeature(new OpenLayers.Feature.Vector()); + t.eq(log[0]._createSymbolizer, undefined, "no _createSymbolizer function for static styles"); + + var styleMap = new OpenLayers.StyleMap(new OpenLayers.Style({foo: "${bar}"}, + {context: {"bar": function(feature){ return "baz" }}} + )); + layer.styleMap = styleMap; + layer.drawFeature(new OpenLayers.Feature.Vector()); + t.eq(log[1]._createSymbolizer().foo, "baz", "_createSymbolizer function added to style and returns correct result"); + OpenLayers.Renderer.NG = OrigRendererNG; + + layer.renderer = renderer; + layer.drawFeature(new OpenLayers.Feature.Vector()); + t.eq(log[2]._createSymbolizer, undefined, "no _createSymbolizer function for non-NG renderer"); + } function test_deleted_state(t) { t.plan(9); @@ -869,6 +906,23 @@ "featuresadded event received expected number of features"); } + function test_raiseFeature(t) { + t.plan(4); + var map = new OpenLayers.Map('map'); + layer = new OpenLayers.Layer.Vector(""); + map.addLayer(layer); + var feature1 = new OpenLayers.Feature.Vector(new OpenLayers.Geometry(1.0, 1.0)); + var feature2 = new OpenLayers.Feature.Vector(new OpenLayers.Geometry(2.0, 2.0)); + layer.addFeatures([feature1,feature2]); + layer.raiseFeature(feature1, 1); + t.eq(layer.features.indexOf(feature1), 1, "first feature raised one up"); + layer.raiseFeature(feature1, -1); + t.eq(layer.features.indexOf(feature1), 0, "first feature raised one down"); + layer.raiseFeature(feature1, -1); + t.eq(layer.features.indexOf(feature1), 0, "feature stays at index 0 because there is no lower position than index 0."); + layer.raiseFeature(feature1, 2); + t.eq(layer.features.indexOf(feature1), 1, "first feature raised 2 up, but has index 1 because there are only two features in layer."); + } From 5bffb3dea3ac23cc50a8ee88c8e2ff58c11fc2f5 Mon Sep 17 00:00:00 2001 From: mosesonline Date: Fri, 7 Dec 2012 12:46:28 +0100 Subject: [PATCH 004/123] Update lib/OpenLayers/Handler/Feature.js simplify code a little --- lib/OpenLayers/Handler/Feature.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/OpenLayers/Handler/Feature.js b/lib/OpenLayers/Handler/Feature.js index 63d64b1f63..c71d141151 100644 --- a/lib/OpenLayers/Handler/Feature.js +++ b/lib/OpenLayers/Handler/Feature.js @@ -325,10 +325,8 @@ OpenLayers.Handler.Feature = OpenLayers.Class(OpenLayers.Handler, { // we enter handle. Yes, a bit hackish... this.feature = null; } - } else { - if(this.lastFeature && (previouslyIn || click)) { - this.triggerCallback(type, 'out', [this.lastFeature]); - } + } else if(this.lastFeature && (previouslyIn || click)) { + this.triggerCallback(type, 'out', [this.lastFeature]); } return handled; }, From 9ea9b859880ea900e6c1e3211f1f4f3d8ae0b6d6 Mon Sep 17 00:00:00 2001 From: mosesonline Date: Tue, 11 Dec 2012 07:27:09 +0100 Subject: [PATCH 005/123] Revert "[New] raise feature function to move features in layer." This reverts commit cb1c3a834aedea34e98fe20df112304316287004. the drawing order is controlled by Renderer not the Layer classes --- lib/OpenLayers/Layer/Vector.js | 23 +------------- tests/Layer/Vector.html | 56 +--------------------------------- 2 files changed, 2 insertions(+), 77 deletions(-) diff --git a/lib/OpenLayers/Layer/Vector.js b/lib/OpenLayers/Layer/Vector.js index ddd2f6f4a0..4300e59b16 100644 --- a/lib/OpenLayers/Layer/Vector.js +++ b/lib/OpenLayers/Layer/Vector.js @@ -699,28 +699,7 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, { this.events.triggerEvent("featuresremoved", {features: features}); } }, - - /** - * APIMethod: raiseFeature - * Changes the index of the given feature by delta and redraws the layer. If delta is positive, the feature is moved up the layer's feature stack; if delta is negative, the feature is moved down. - * If delta + current is negative it is set to 0 and feature will be at the bottom; if it is bigger then the features count than it is set to the last index and the feature will be at the top. - */ - raiseFeature:function(feature, delta) { - var base = this.features.indexOf(feature); - var idx = base + delta; - if (idx < 0) { - idx = 0; - } else if (idx > this.features.length) { - idx = this.features.length; - } - if (base != idx) { - this.features.splice(base, 1); - this.features.splice(idx, 0, feature); - this.eraseFeatures(this.features); - this.redraw(); - } - }, - + /** * APIMethod: removeAllFeatures * Remove all features from the layer. diff --git a/tests/Layer/Vector.html b/tests/Layer/Vector.html index 2cfc9c07bd..aa3e2f8a7e 100644 --- a/tests/Layer/Vector.html +++ b/tests/Layer/Vector.html @@ -461,44 +461,7 @@ layer.features = []; } - function test_drawfeature_ng(t) { - t.plan(3); - var layer = new OpenLayers.Layer.Vector(); - layer.drawn = true; - var log = []; - - // Bogus layer renderer needs some methods - // for functional tests. - var renderer = { - initialize: function() {}, - drawFeature: function(feature, style) { - log.push(style); - }, - root: document.createElement("div"), - destroy: function() { }, - eraseFeatures: function() {}, - setExtent: function() {}, - setSize: function() {} - }; - var OrigRendererNG = OpenLayers.Renderer.NG; - OpenLayers.Renderer.NG = OpenLayers.Class(renderer); - - layer.renderer = new OpenLayers.Renderer.NG(); - layer.drawFeature(new OpenLayers.Feature.Vector()); - t.eq(log[0]._createSymbolizer, undefined, "no _createSymbolizer function for static styles"); - - var styleMap = new OpenLayers.StyleMap(new OpenLayers.Style({foo: "${bar}"}, - {context: {"bar": function(feature){ return "baz" }}} - )); - layer.styleMap = styleMap; - layer.drawFeature(new OpenLayers.Feature.Vector()); - t.eq(log[1]._createSymbolizer().foo, "baz", "_createSymbolizer function added to style and returns correct result"); - OpenLayers.Renderer.NG = OrigRendererNG; - - layer.renderer = renderer; - layer.drawFeature(new OpenLayers.Feature.Vector()); - t.eq(log[2]._createSymbolizer, undefined, "no _createSymbolizer function for non-NG renderer"); - } + function test_deleted_state(t) { t.plan(9); @@ -906,23 +869,6 @@ "featuresadded event received expected number of features"); } - function test_raiseFeature(t) { - t.plan(4); - var map = new OpenLayers.Map('map'); - layer = new OpenLayers.Layer.Vector(""); - map.addLayer(layer); - var feature1 = new OpenLayers.Feature.Vector(new OpenLayers.Geometry(1.0, 1.0)); - var feature2 = new OpenLayers.Feature.Vector(new OpenLayers.Geometry(2.0, 2.0)); - layer.addFeatures([feature1,feature2]); - layer.raiseFeature(feature1, 1); - t.eq(layer.features.indexOf(feature1), 1, "first feature raised one up"); - layer.raiseFeature(feature1, -1); - t.eq(layer.features.indexOf(feature1), 0, "first feature raised one down"); - layer.raiseFeature(feature1, -1); - t.eq(layer.features.indexOf(feature1), 0, "feature stays at index 0 because there is no lower position than index 0."); - layer.raiseFeature(feature1, 2); - t.eq(layer.features.indexOf(feature1), 1, "first feature raised 2 up, but has index 1 because there are only two features in layer."); - } From ee5796cb785836c5d8d87b36261df73820851929 Mon Sep 17 00:00:00 2001 From: Pierre GIRAUD Date: Mon, 3 Dec 2012 15:26:49 +0100 Subject: [PATCH 006/123] Send zoomChanged value when triggering movestart event --- lib/OpenLayers/Map.js | 4 +++- tests/Map.html | 9 +++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/OpenLayers/Map.js b/lib/OpenLayers/Map.js index 50eb3bc8c9..cf5d1d0d97 100644 --- a/lib/OpenLayers/Map.js +++ b/lib/OpenLayers/Map.js @@ -1908,7 +1908,9 @@ OpenLayers.Map = OpenLayers.Class({ // if neither center nor zoom will change, no need to do anything if (zoomChanged || centerChanged || dragging) { - dragging || this.events.triggerEvent("movestart"); + dragging || this.events.triggerEvent("movestart", { + zoomChanged: zoomChanged + }); if (centerChanged) { if (!zoomChanged && this.center) { diff --git a/tests/Map.html b/tests/Map.html index ffa5234b61..b072585a2b 100644 --- a/tests/Map.html +++ b/tests/Map.html @@ -977,7 +977,7 @@ } function test_Map_moveTo(t) { - t.plan(8); + t.plan(12); map = new OpenLayers.Map('map'); var baseLayer = new OpenLayers.Layer.WMS("Test Layer", @@ -992,10 +992,15 @@ property: event.property }); }); - baseLayer.events.on({ + map.events.on({ move: function() { t.ok(true, "move listener called"); }, + movestart: function(e) { + t.eq(e.zoomChanged, true, "movestart listener called with expected value"); + } + }); + baseLayer.events.on({ moveend: function(e) { t.eq(e.zoomChanged, true, "moveend listener called with expected value"); } From 0a131f380a4c31308d7c53ab5ae47baaa9436ee0 Mon Sep 17 00:00:00 2001 From: Pierre GIRAUD Date: Fri, 30 Nov 2012 13:29:12 +0100 Subject: [PATCH 007/123] Adding preserveCenter config option --- examples/mobile.js | 3 +++ lib/OpenLayers/Control/PinchZoom.js | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/examples/mobile.js b/examples/mobile.js index 9bbcb9125a..3104cbbd63 100644 --- a/examples/mobile.js +++ b/examples/mobile.js @@ -22,6 +22,9 @@ var init = function () { controls: [ new OpenLayers.Control.Attribution(), new OpenLayers.Control.TouchNavigation({ + pinchZoomOptions: { + preserveCenter: true + }, dragPanOptions: { enableKinetic: true } diff --git a/lib/OpenLayers/Control/PinchZoom.js b/lib/OpenLayers/Control/PinchZoom.js index b3691d813b..e89fa287f6 100644 --- a/lib/OpenLayers/Control/PinchZoom.js +++ b/lib/OpenLayers/Control/PinchZoom.js @@ -40,6 +40,12 @@ OpenLayers.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, { * true. */ autoActivate: true, + + /** + * APIProperty: preserveCenter + * {Boolean} Force the map center to stay in place. Default is false. + */ + preserveCenter: false, /** * APIProperty: handlerOptions @@ -73,8 +79,10 @@ OpenLayers.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, { * of the pinch gesture. This give us the current scale of the pinch. */ pinchStart: function(evt, pinchData) { - this.pinchOrigin = evt.xy; - this.currentCenter = evt.xy; + var xy = (this.preserveCenter) ? + this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy; + this.pinchOrigin = xy; + this.currentCenter = xy; }, /** @@ -89,7 +97,8 @@ OpenLayers.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, { var scale = pinchData.scale; var containerOrigin = this.map.layerContainerOriginPx; var pinchOrigin = this.pinchOrigin; - var current = evt.xy; + var current = (this.preserveCenter) ? + this.map.getPixelFromLonLat(this.map.getCenter()) : evt.xy; var dx = Math.round((current.x - pinchOrigin.x) + (scale - 1) * (containerOrigin.x - pinchOrigin.x)); var dy = Math.round((current.y - pinchOrigin.y) + (scale - 1) * (containerOrigin.y - pinchOrigin.y)); From 00c3ca47c0bc4df5ce869766d676440a23b7e2a8 Mon Sep 17 00:00:00 2001 From: Pierre GIRAUD Date: Mon, 3 Dec 2012 15:25:31 +0100 Subject: [PATCH 008/123] Adding test for new preserveCenter option --- tests/Control/PinchZoom.html | 47 ++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/Control/PinchZoom.html b/tests/Control/PinchZoom.html index 788642d3da..9fc4a189b6 100644 --- a/tests/Control/PinchZoom.html +++ b/tests/Control/PinchZoom.html @@ -79,6 +79,53 @@ } + function test_pinchMove_preservecenter(t) { + + var control = new OpenLayers.Control.PinchZoom({ + preserveCenter: true + }); + + var map = new OpenLayers.Map({ + div: "map", + controls: [control], + layers: [new OpenLayers.Layer('fake', {isBaseLayer: true})] + }); + map.zoomToMaxExtent(); + + centerPx = map.getPixelFromLonLat(map.getCenter()); + + control.pinchStart = function(evt, pinchData) { + t.eq(control.pinchOrigin, centerPx, "center preserved"); + t.eq(control.currentCenter, centerPx, "center preserved"); + } + + control.pinchStart(null); + + var log = []; + control.applyTransform = function(transform) { + log.push(transform); + } + control.pinchOrigin = map.getPixelFromLonLat(map.getCenter()); + + var cases = [ + {scale: 1, transform: "translate(0px, 0px) scale(1)"}, + {scale: 2, transform: "translate(-128px, -128px) scale(2)"}, + {scale: 2.5, transform: "translate(-192px, -192px) scale(2.5)"}, + {scale: 0.25, transform: "translate(96px, 96px) scale(0.25)"} + ]; + + var len = cases.length; + t.plan(2 + len*2); + + var c; + for (var i=0; i From 69580cd6981ef0eadc00dd4f4f744359168584c6 Mon Sep 17 00:00:00 2001 From: Pierre GIRAUD Date: Mon, 17 Dec 2012 12:56:09 +0100 Subject: [PATCH 009/123] Don't change the example --- examples/mobile.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/mobile.js b/examples/mobile.js index 3104cbbd63..9bbcb9125a 100644 --- a/examples/mobile.js +++ b/examples/mobile.js @@ -22,9 +22,6 @@ var init = function () { controls: [ new OpenLayers.Control.Attribution(), new OpenLayers.Control.TouchNavigation({ - pinchZoomOptions: { - preserveCenter: true - }, dragPanOptions: { enableKinetic: true } From 06597f1897e565f3610243eefde90f5b38a0378b Mon Sep 17 00:00:00 2001 From: Pierre GIRAUD Date: Mon, 17 Dec 2012 13:23:10 +0100 Subject: [PATCH 010/123] Missing var --- tests/Control/PinchZoom.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Control/PinchZoom.html b/tests/Control/PinchZoom.html index 9fc4a189b6..1aa68f9c04 100644 --- a/tests/Control/PinchZoom.html +++ b/tests/Control/PinchZoom.html @@ -92,7 +92,7 @@ }); map.zoomToMaxExtent(); - centerPx = map.getPixelFromLonLat(map.getCenter()); + var centerPx = map.getPixelFromLonLat(map.getCenter()); control.pinchStart = function(evt, pinchData) { t.eq(control.pinchOrigin, centerPx, "center preserved"); From d0c85850f5b21c83caaf642cbab8fdc32a9e00f2 Mon Sep 17 00:00:00 2001 From: Pierre GIRAUD Date: Mon, 17 Dec 2012 13:34:00 +0100 Subject: [PATCH 011/123] More detailed documentation --- lib/OpenLayers/Control/PinchZoom.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/OpenLayers/Control/PinchZoom.js b/lib/OpenLayers/Control/PinchZoom.js index e89fa287f6..f55d08e9fc 100644 --- a/lib/OpenLayers/Control/PinchZoom.js +++ b/lib/OpenLayers/Control/PinchZoom.js @@ -43,7 +43,12 @@ OpenLayers.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, { /** * APIProperty: preserveCenter - * {Boolean} Force the map center to stay in place. Default is false. + * {Boolean} Set this to true if you don't want the map center to change + * while pinching. For example you may want to set preserveCenter to + * true when the user location is being watched and you want to preserve + * the user location at the center of the map even if he zooms in or + * out using pinch. This property's value can be changed any time on an + * existing instance. Default is false. */ preserveCenter: false, From 6c21c2043fac92e5c78cbe3835d3ca79cfe58028 Mon Sep 17 00:00:00 2001 From: Pierre GIRAUD Date: Mon, 17 Dec 2012 13:55:32 +0100 Subject: [PATCH 012/123] Completing the doc strings --- lib/OpenLayers/Map.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/OpenLayers/Map.js b/lib/OpenLayers/Map.js index cf5d1d0d97..ba7e7006fe 100644 --- a/lib/OpenLayers/Map.js +++ b/lib/OpenLayers/Map.js @@ -75,7 +75,9 @@ OpenLayers.Map = OpenLayers.Class({ * The *layer* property will be a reference to the changed layer. The * *property* property will be a key to the changed property (name, * order, opacity, params, visibility or attribution). - * movestart - triggered after the start of a drag, pan, or zoom + * movestart - triggered after the start of a drag, pan, or zoom. The event + * object may include a *zoomChanged* property that tells whether the + * zoom has changed. * move - triggered after each drag, pan, or zoom * moveend - triggered after a drag, pan, or zoom completes * zoomend - triggered after a zoom completes From f0f1ea086753455ee883b2694eff9ea3f8976b05 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Mon, 17 Dec 2012 14:54:08 +0100 Subject: [PATCH 013/123] Skip frames when minimum frame rate is not reached The new minFrameRate option is used to make sure that an animation does not run longer than the time calculated from that frame rate. Time is made up by skipping frames, i.e. skipping execution of the eachStep callback. --- lib/OpenLayers/Tween.js | 22 +++++++++++++++++++++- tests/Tween.html | 30 ++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/lib/OpenLayers/Tween.js b/lib/OpenLayers/Tween.js index 4e504381a5..14e77210b8 100644 --- a/lib/OpenLayers/Tween.js +++ b/lib/OpenLayers/Tween.js @@ -52,6 +52,22 @@ OpenLayers.Tween = OpenLayers.Class({ */ time: null, + /** + * APIProperty: minFrameRate + * {Number} The minimum framerate for animations. After each step, the time + * spent in the animation is compared to the calculated time at this frame + * rate. If the animation runs longer than the calculated time, the next + * step is skipped. + */ + minFrameRate: 30, + + /** + * Property: startTime + * {Number} The timestamp of the first execution step. Used for skipping + * frames + */ + startTime: null, + /** * Property: animationId * {int} Loop id returned by OpenLayers.Animation.start @@ -92,6 +108,7 @@ OpenLayers.Tween = OpenLayers.Class({ this.duration = duration; this.callbacks = options.callbacks; this.time = 0; + this.startTime = new Date().getTime(); OpenLayers.Animation.stop(this.animationId); this.animationId = null; if (this.callbacks && this.callbacks.start) { @@ -139,7 +156,10 @@ OpenLayers.Tween = OpenLayers.Class({ this.time++; if (this.callbacks && this.callbacks.eachStep) { - this.callbacks.eachStep.call(this, value); + // skip frames if frame rate drops below threshold + if ((new Date().getTime() - this.startTime) / this.time <= 1000 / this.minFrameRate) { + this.callbacks.eachStep.call(this, value); + } } if (this.time > this.duration) { diff --git a/tests/Tween.html b/tests/Tween.html index fdd8fa7016..5c52b84e26 100644 --- a/tests/Tween.html +++ b/tests/Tween.html @@ -74,6 +74,36 @@ tween.stop(); t.ok(tween.animationId != null, "stop method doesn't do anything if tween isn't running"); } + + function test_Tween_skip(t) { + t.plan(2); + + var tween = new OpenLayers.Tween(); + var log1 = 0; + tween.start({count: 0}, {count: 10}, 10, { + callbacks: { + eachStep: function() { + log1++; + } + }, + minFrameRate: 10000 + }); + + var log2 = 0; + tween.start({count: 0}, {count: 10}, 10, { + callbacks: { + eachStep: function() { + log2++; + } + }, + minFrameRate: 1 + }); + + t.delay_call(0.8, function() { + t.eq(log1, 0, 'all frames skipped at a frame rate of 10000'); + t.eq(log2, 11, 'no frames skipped at a frame rate of 1'); + }); + } From 0cdb3aeb5267f77bbc6571b3bd4be1da40c4b5e7 Mon Sep 17 00:00:00 2001 From: mosesonline Date: Tue, 18 Dec 2012 09:34:48 +0100 Subject: [PATCH 014/123] [BugFix] Fix selectFeatures is null exception when layer is destroyed. Since you can listen only to preremovelayer to handle removing layer with SelectFeature. But preremovelayer is triggered after selectFeatures is set to null. --- lib/OpenLayers/Control/SelectFeature.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/OpenLayers/Control/SelectFeature.js b/lib/OpenLayers/Control/SelectFeature.js index 198cef9b1b..654a1f77a7 100644 --- a/lib/OpenLayers/Control/SelectFeature.js +++ b/lib/OpenLayers/Control/SelectFeature.js @@ -305,14 +305,16 @@ OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, { for(l=0; l numExcept) { - feature = layer.selectedFeatures[numExcept]; - if(!options || options.except != feature) { - this.unselect(feature); - } else { - ++numExcept; + if(layer.selectedFeatures != null) { + while(layer.selectedFeatures.length > numExcept) { + feature = layer.selectedFeatures[numExcept]; + if(!options || options.except != feature) { + this.unselect(feature); + } else { + ++numExcept; + } } - } + } } }, From 7aed43185b77b7945fe65b5879039232101283ad Mon Sep 17 00:00:00 2001 From: mosesonline Date: Tue, 18 Dec 2012 09:43:22 +0100 Subject: [PATCH 015/123] [BugFix] Added tests for handle destroyed layer in SelectFeature. --- tests/Control/SelectFeature.html | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/Control/SelectFeature.html b/tests/Control/SelectFeature.html index 150ab07c5c..b0d7d885a1 100644 --- a/tests/Control/SelectFeature.html +++ b/tests/Control/SelectFeature.html @@ -545,6 +545,31 @@ t.eq((control.layers === null), true, "When using setLayer with a single layer, the layers property is removed if present before"); map.destroy(); } + + function test_setLayerWithRemoved(t) { + t.plan(2); + var map = new OpenLayers.Map("map"); + var layer1 = new OpenLayers.Layer.Vector(); + var layer2 = new OpenLayers.Layer.Vector(); + map.addLayer(layer1, layer2); + // initialize it with a single layer + var control = new OpenLayers.Control.SelectFeature(layer1); + map.addControl(control); + control.activate(); + var noError = true; + map.events.register("preremovelayer", this, function(e) { + try { + control.setLayer(layer2); + } catch (e) { + noError = false; + } + }); + layer1.destroy(); + t.eq(layer2.id, control.layer.id, "Layer is set correctly without error"); + t.eq(noError, true,"No error occured during setLayer"); + control.destroy(); + map.destroy(); + } function test_destroy(t) { t.plan(1); From 0263b2b5e1406a77c824664764996a53a6735d9e Mon Sep 17 00:00:00 2001 From: mosesonline Date: Tue, 18 Dec 2012 09:47:33 +0100 Subject: [PATCH 016/123] [Change] renamed test and added print of error --- tests/Control/SelectFeature.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Control/SelectFeature.html b/tests/Control/SelectFeature.html index b0d7d885a1..6e522e77f9 100644 --- a/tests/Control/SelectFeature.html +++ b/tests/Control/SelectFeature.html @@ -546,7 +546,7 @@ map.destroy(); } - function test_setLayerWithRemoved(t) { + function test_setLayerWithRemoving(t) { t.plan(2); var map = new OpenLayers.Map("map"); var layer1 = new OpenLayers.Layer.Vector(); @@ -556,17 +556,17 @@ var control = new OpenLayers.Control.SelectFeature(layer1); map.addControl(control); control.activate(); - var noError = true; + var noError = null; map.events.register("preremovelayer", this, function(e) { try { control.setLayer(layer2); } catch (e) { - noError = false; + noError = e; } }); layer1.destroy(); t.eq(layer2.id, control.layer.id, "Layer is set correctly without error"); - t.eq(noError, true,"No error occured during setLayer"); + t.eq(noError, null,"No error occured during setLayer. Error is: '"+noError+"'"); control.destroy(); map.destroy(); } From 6c5119455d52cb266bf3c463004522ca448407f8 Mon Sep 17 00:00:00 2001 From: Christopher Eykamp Date: Wed, 19 Dec 2012 18:11:14 +0100 Subject: [PATCH 017/123] Basic WCS testing in place. Tests are basically meaningless at this point. --- lib/OpenLayers.js | 8 ++++++++ tests/list-tests.html | 2 ++ 2 files changed, 10 insertions(+) diff --git a/lib/OpenLayers.js b/lib/OpenLayers.js index 4df00ddf62..711ab6606c 100644 --- a/lib/OpenLayers.js +++ b/lib/OpenLayers.js @@ -280,6 +280,10 @@ "OpenLayers/Filter/Function.js", "OpenLayers/Protocol.js", "OpenLayers/Protocol/HTTP.js", + "OpenLayers/Protocol/WCS.js", + "OpenLayers/Protocol/WCS/v1.js", + "OpenLayers/Protocol/WCS/v1_0_0.js", + "OpenLayers/Protocol/WCS/v1_1_0.js", "OpenLayers/Protocol/WFS.js", "OpenLayers/Protocol/WFS/v1.js", "OpenLayers/Protocol/WFS/v1_0_0.js", @@ -313,6 +317,10 @@ "OpenLayers/Format/OWSCommon/v1.js", "OpenLayers/Format/OWSCommon/v1_0_0.js", "OpenLayers/Format/OWSCommon/v1_1_0.js", + "OpenLayers/Format/WCSCapabilities.js", + "OpenLayers/Format/WCSCapabilities/v1.js", + "OpenLayers/Format/WCSCapabilities/v1_0_0.js", + "OpenLayers/Format/WCSCapabilities/v1_1_0.js", "OpenLayers/Format/WFSCapabilities.js", "OpenLayers/Format/WFSCapabilities/v1.js", "OpenLayers/Format/WFSCapabilities/v1_0_0.js", diff --git a/tests/list-tests.html b/tests/list-tests.html index 8c37464b84..3b24400fa3 100644 --- a/tests/list-tests.html +++ b/tests/list-tests.html @@ -84,6 +84,8 @@
  • Format/Filter/v1_0_0.html
  • Format/Filter/v1_1_0.html
  • Format/QueryStringFilter.html
  • +
  • Format/WCSCapabilities.html
  • +
  • Format/WCSCapabilities/v1.html
  • Format/WFS.html
  • Format/WFSCapabilities.html
  • Format/WFSCapabilities/v1.html
  • From 893966dfae6e9f2e376e08eccbf6b4474de56cd7 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Wed, 19 Dec 2012 22:23:45 +0100 Subject: [PATCH 018/123] 'm' and 'Meters' in OpenLayers.INCHES_PER_UNIT are not the same OpenLayers.INCHES_PER_UNIT.m should equal OpenLayers.INCHES_PER_UNIT.Meters, just like OpenLayers.INCHES_PER_UNIT.km should equal OpenLayers.Inches_PER_UNIT.Kilometers. This confusion probably comes from mixing International inches with US Survey inches when compiling the unit conversion list (1 meter is 39.37007874 International inches, but 39.37 US Survey inches. It may not be obvious, but 'inches'/'Inch' in OpenLayers means US Survey inch, and 'IInch' means International inch). This change also fixes offsets caused by incorrect resolution calculations in OpenLayers.Format.WMTSCapabilities. --- lib/OpenLayers/Util.js | 4 ++-- tests/Util.html | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/OpenLayers/Util.js b/lib/OpenLayers/Util.js index f4948edc37..a8c4a5de42 100644 --- a/lib/OpenLayers/Util.js +++ b/lib/OpenLayers/Util.js @@ -962,8 +962,8 @@ OpenLayers.INCHES_PER_UNIT = { 'inches': 1.0, 'ft': 12.0, 'mi': 63360.0, - 'm': 39.3701, - 'km': 39370.1, + 'm': 39.37, + 'km': 39370, 'dd': 4374754, 'yd': 36 }; diff --git a/tests/Util.html b/tests/Util.html index 4a7507e451..3972d68d84 100644 --- a/tests/Util.html +++ b/tests/Util.html @@ -706,6 +706,12 @@ t.ok(OpenLayers.String.startsWith(id, "chicken"), "OpenLayers.Util.createUniqueID starts id correctly"); } + + function test_units(t) { + t.plan(2); + t.eq(OpenLayers.INCHES_PER_UNIT.m, OpenLayers.INCHES_PER_UNIT.Meter, 'Same inches per m and Meters'); + t.eq(OpenLayers.INCHES_PER_UNIT.km, OpenLayers.INCHES_PER_UNIT.Kilometer, 'Same inches per km and Kilometers'); + } function test_Util_normalizeScale(t) { t.plan(2); @@ -728,7 +734,7 @@ var scale = 1/150000000; var resolution = OpenLayers.Util.getResolutionFromScale(scale, 'm'); - t.eq(resolution.toFixed(6), "52916.638092", "Calculated correct resolution for " + scale); + t.eq(resolution.toFixed(6), "52916.772500", "Calculated correct resolution for " + scale); scale = 150000000; resolution = OpenLayers.Util.getResolutionFromScale(scale); From f5d7f794c9c9d7a3a41b774c910f4f5f0573771e Mon Sep 17 00:00:00 2001 From: ahocevar Date: Wed, 19 Dec 2012 23:13:11 +0100 Subject: [PATCH 019/123] Some tweaks to make tests pass again --- tests/Format/WMSCapabilities/v1_1_1.html | 4 ++-- tests/Layer.html | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/Format/WMSCapabilities/v1_1_1.html b/tests/Format/WMSCapabilities/v1_1_1.html index 0d044e480c..e3b0863624 100644 --- a/tests/Format/WMSCapabilities/v1_1_1.html +++ b/tests/Format/WMSCapabilities/v1_1_1.html @@ -340,7 +340,7 @@ // needed for the minScale/maxScale test, see below var dpi = OpenLayers.DOTS_PER_INCH; - OpenLayers.DOTS_PER_INCH = 90.71; + OpenLayers.DOTS_PER_INCH = 90.710230403857; var xml = document.getElementById("ogcsample").firstChild.nodeValue; var doc = new OpenLayers.Format.XML().read(xml); @@ -377,7 +377,7 @@ - corresponds to (RESOLUTION keyword in MAP file has value of 90.71): + corresponds to (RESOLUTION keyword in MAP file has value of 90.710230403857): MAXSCALE 250000 MINSCALE 1000 diff --git a/tests/Layer.html b/tests/Layer.html index 22935f7e3a..85f22aae6a 100644 --- a/tests/Layer.html +++ b/tests/Layer.html @@ -315,7 +315,7 @@ for (var i=0; i Date: Thu, 20 Dec 2012 08:55:21 +0100 Subject: [PATCH 020/123] Update lib/OpenLayers/Control/SelectFeature.js indentation fixed and added comment to explain null case --- lib/OpenLayers/Control/SelectFeature.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/OpenLayers/Control/SelectFeature.js b/lib/OpenLayers/Control/SelectFeature.js index 654a1f77a7..837487cdc5 100644 --- a/lib/OpenLayers/Control/SelectFeature.js +++ b/lib/OpenLayers/Control/SelectFeature.js @@ -305,7 +305,10 @@ OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, { for(l=0; l numExcept) { feature = layer.selectedFeatures[numExcept]; if(!options || options.except != feature) { @@ -314,7 +317,7 @@ OpenLayers.Control.SelectFeature = OpenLayers.Class(OpenLayers.Control, { ++numExcept; } } - } + } } }, From fc64b2c5f86534b44fdcb3b6fe70e1b3b4197138 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Thu, 20 Dec 2012 16:30:58 +0100 Subject: [PATCH 021/123] Fixing tests properly, as suggested by @sbrunner --- tests/Layer.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/Layer.html b/tests/Layer.html index 85f22aae6a..1c3db10577 100644 --- a/tests/Layer.html +++ b/tests/Layer.html @@ -315,7 +315,7 @@ for (var i=0; i Date: Fri, 21 Dec 2012 12:33:28 +0100 Subject: [PATCH 022/123] Use transitionend listeners where available In addition to relying on removeBackBufferDelay, we can remove the backbuffer earlier without flicker in an ontransitionend listener on the last loaded tile. --- lib/OpenLayers/Layer/Grid.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index 815eb0d0ae..c2ad2abfaa 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -300,6 +300,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { arguments); this.grid = []; this.tileQueue = []; + this._removeBackBuffer = OpenLayers.Function.bind(this.removeBackBuffer, this); if (this.removeBackBufferDelay === null) { this.removeBackBufferDelay = this.singleTile ? 0 : 2500; @@ -757,6 +758,12 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { * Remove back buffer from DOM. */ removeBackBuffer: function() { + if (this._transitionElement) { + OpenLayers.Event.stopObserving(this._transitionElement, 'transitionend', this._removeBackBuffer); + OpenLayers.Event.stopObserving(this._transitionElement, 'webkitTransitionEnd', this._removeBackBuffer); + OpenLayers.Event.stopObserving(this._transitionElement, 'otransitionend', this._removeBackBuffer); + delete this._transitionElement; + } if(this.backBuffer) { this.div.removeChild(this.backBuffer); this.backBuffer = null; @@ -1120,11 +1127,13 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { this.loading = false; this.events.triggerEvent("loadend"); if(this.backBuffer) { - // the removal of the back buffer is delayed to prevent flash - // effects due to the animation of tile displaying + this._transitionElement = tile.imgDiv; + OpenLayers.Event.observe(this._transitionElement, 'transitionend', this._removeBackBuffer); + OpenLayers.Event.observe(this._transitionElement, 'webkitTransitionEnd', this._removeBackBuffer); + OpenLayers.Event.observe(this._transitionElement, 'otransitionend', this._removeBackBuffer); + // the removal of the back buffer is delayed to prevent // flash effects due to the animation of tile displaying this.backBufferTimerId = window.setTimeout( - OpenLayers.Function.bind(this.removeBackBuffer, this), - this.removeBackBufferDelay + this._removeBackBuffer, this.removeBackBufferDelay ); } } From 43c646b6da507cb2a667fd7418f3ceb7bada6ed6 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Fri, 21 Dec 2012 13:01:15 +0100 Subject: [PATCH 023/123] Use new Opera event name as well As pointed out by @bartvde, according to http://stackoverflow.com/questions/5819912/webkit-transition-end-in-mozilla-and-opera, Opera uses otransitionend or oTransitionEnd, depending on the version. --- lib/OpenLayers/Layer/Grid.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index c2ad2abfaa..7819fe3396 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -762,6 +762,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { OpenLayers.Event.stopObserving(this._transitionElement, 'transitionend', this._removeBackBuffer); OpenLayers.Event.stopObserving(this._transitionElement, 'webkitTransitionEnd', this._removeBackBuffer); OpenLayers.Event.stopObserving(this._transitionElement, 'otransitionend', this._removeBackBuffer); + OpenLayers.Event.stopObserving(this._transitionElement, 'oTransitionEnd', this._removeBackBuffer); delete this._transitionElement; } if(this.backBuffer) { @@ -1131,6 +1132,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { OpenLayers.Event.observe(this._transitionElement, 'transitionend', this._removeBackBuffer); OpenLayers.Event.observe(this._transitionElement, 'webkitTransitionEnd', this._removeBackBuffer); OpenLayers.Event.observe(this._transitionElement, 'otransitionend', this._removeBackBuffer); + OpenLayers.Event.observe(this._transitionElement, 'oTransitionEnd', this._removeBackBuffer); // the removal of the back buffer is delayed to prevent // flash effects due to the animation of tile displaying this.backBufferTimerId = window.setTimeout( this._removeBackBuffer, this.removeBackBufferDelay From fcd8586883df12dc6f63dfdec1065d2c92720725 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Fri, 21 Dec 2012 13:07:36 +0100 Subject: [PATCH 024/123] Using an array for the transitionend event names --- lib/OpenLayers/Layer/Grid.js | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index 7819fe3396..a8c1912730 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -285,6 +285,15 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { */ rowSign: null, + /** + * Property: transitionendEvents + * {Array} Event names for transitionend + */ + transitionendEvents: [ + 'transitionend', 'webkitTransitionEnd', 'otransitionend', + 'oTransitionEnd' + ], + /** * Constructor: OpenLayers.Layer.Grid * Create a new grid layer @@ -759,10 +768,10 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { */ removeBackBuffer: function() { if (this._transitionElement) { - OpenLayers.Event.stopObserving(this._transitionElement, 'transitionend', this._removeBackBuffer); - OpenLayers.Event.stopObserving(this._transitionElement, 'webkitTransitionEnd', this._removeBackBuffer); - OpenLayers.Event.stopObserving(this._transitionElement, 'otransitionend', this._removeBackBuffer); - OpenLayers.Event.stopObserving(this._transitionElement, 'oTransitionEnd', this._removeBackBuffer); + for (var i=this.transitionendEvents.length-1; i>=0; --i) { + OpenLayers.Event.stopObserving(this._transitionElement, + this.transitionendEvents[i], this._removeBackBuffer); + } delete this._transitionElement; } if(this.backBuffer) { @@ -1129,10 +1138,11 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { this.events.triggerEvent("loadend"); if(this.backBuffer) { this._transitionElement = tile.imgDiv; - OpenLayers.Event.observe(this._transitionElement, 'transitionend', this._removeBackBuffer); - OpenLayers.Event.observe(this._transitionElement, 'webkitTransitionEnd', this._removeBackBuffer); - OpenLayers.Event.observe(this._transitionElement, 'otransitionend', this._removeBackBuffer); - OpenLayers.Event.observe(this._transitionElement, 'oTransitionEnd', this._removeBackBuffer); + for (var i=this.transitionendEvents.length-1; i>=0; --i) { + OpenLayers.Event.observe(this._transitionElement, + this.transitionendEvents[i], + this._removeBackBuffer); + } // the removal of the back buffer is delayed to prevent // flash effects due to the animation of tile displaying this.backBufferTimerId = window.setTimeout( this._removeBackBuffer, this.removeBackBufferDelay From 810d9ea95df8e39f41bec904ed92714c56dffc4c Mon Sep 17 00:00:00 2001 From: ahocevar Date: Fri, 21 Dec 2012 13:10:26 +0100 Subject: [PATCH 025/123] Fixing line breaks. --- lib/OpenLayers/Layer/Grid.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index a8c1912730..8791236cb6 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -1143,7 +1143,8 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { this.transitionendEvents[i], this._removeBackBuffer); } - // the removal of the back buffer is delayed to prevent // flash effects due to the animation of tile displaying + // the removal of the back buffer is delayed to prevent + // flash effects due to the animation of tile displaying this.backBufferTimerId = window.setTimeout( this._removeBackBuffer, this.removeBackBufferDelay ); From 5c07ae47bb13f56ea560f522f60b65d651ef9488 Mon Sep 17 00:00:00 2001 From: Christopher Eykamp Date: Fri, 21 Dec 2012 13:15:01 +0100 Subject: [PATCH 026/123] WCS testing more-or-less working, many tests failing, as expected --- lib/OpenLayers/Format/WCSCapabilities.js | 56 +++ lib/OpenLayers/Format/WCSCapabilities/v1.js | 108 +++++ .../Format/WCSCapabilities/v1_0_0.js | 115 +++++ .../Format/WCSCapabilities/v1_1_0.js | 99 ++++ lib/OpenLayers/Protocol/WCS.js | 86 ++++ lib/OpenLayers/Protocol/WCS/v1.js | 434 ++++++++++++++++++ lib/OpenLayers/Protocol/WCS/v1_0_0.js | 43 ++ lib/OpenLayers/Protocol/WCS/v1_1_0.js | 37 ++ tests/Format/WCSCapabilities.html | 43 ++ tests/Format/WCSCapabilities/v1.html | 181 ++++++++ 10 files changed, 1202 insertions(+) create mode 100644 lib/OpenLayers/Format/WCSCapabilities.js create mode 100644 lib/OpenLayers/Format/WCSCapabilities/v1.js create mode 100644 lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js create mode 100644 lib/OpenLayers/Format/WCSCapabilities/v1_1_0.js create mode 100644 lib/OpenLayers/Protocol/WCS.js create mode 100644 lib/OpenLayers/Protocol/WCS/v1.js create mode 100644 lib/OpenLayers/Protocol/WCS/v1_0_0.js create mode 100644 lib/OpenLayers/Protocol/WCS/v1_1_0.js create mode 100644 tests/Format/WCSCapabilities.html create mode 100644 tests/Format/WCSCapabilities/v1.html diff --git a/lib/OpenLayers/Format/WCSCapabilities.js b/lib/OpenLayers/Format/WCSCapabilities.js new file mode 100644 index 0000000000..ae034a5227 --- /dev/null +++ b/lib/OpenLayers/Format/WCSCapabilities.js @@ -0,0 +1,56 @@ +/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/XML/VersionedOGC.js + */ + +/** + * Class: OpenLayers.Format.WCSCapabilities + * Read WCS Capabilities. + * + * Inherits from: + * - + */ +OpenLayers.Format.WCSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC, { + + /** + * APIProperty: defaultVersion + * {String} Version number to assume if none found. Default is "1.1.0". + */ + defaultVersion: "1.1.0", + + /** + * APIProperty: errorProperty + * {String} Which property of the returned object to check for in order to + * determine whether or not parsing has failed. In the case that the + * errorProperty is undefined on the returned object, the document will be + * run through an OGCExceptionReport parser. + */ + errorProperty: "service", + + /** + * Constructor: OpenLayers.Format.WCSCapabilities + * Create a new parser for WCS capabilities. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Read capabilities data from a string, and return a list of layers. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array} List of named layers. + */ + + CLASS_NAME: "OpenLayers.Format.WCSCapabilities" + +}); diff --git a/lib/OpenLayers/Format/WCSCapabilities/v1.js b/lib/OpenLayers/Format/WCSCapabilities/v1.js new file mode 100644 index 0000000000..47aa0b9411 --- /dev/null +++ b/lib/OpenLayers/Format/WCSCapabilities/v1.js @@ -0,0 +1,108 @@ +/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WCSCapabilities.js + */ + +/** + * Class: OpenLayers.Format.WCSCapabilities.v1 + * Abstract class not to be instantiated directly. + * + * Inherits from: + * - + */ +OpenLayers.Format.WCSCapabilities.v1 = OpenLayers.Class( + OpenLayers.Format.XML, { + + /** + * Property: namespaces + * {Object} Mapping of namespace aliases to namespace URIs. + */ + namespaces: { + wcs: "http://www.opengis.net/wcs", + xlink: "http://www.w3.org/1999/xlink", + xsi: "http://www.w3.org/2001/XMLSchema-instance", + ows: "http://www.opengis.net/ows" + }, + + /** + * Property: defaultPrefix + */ + defaultPrefix: "wcs", + + /** + * Constructor: OpenLayers.Format.WCSCapabilities.v1_1 + * Create an instance of one of the subclasses. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * APIMethod: read + * Read capabilities data from a string, and return a list of layers. + * + * Parameters: + * data - {String} or {DOMElement} data to read/parse. + * + * Returns: + * {Array} List of named layers. + */ + read: function(data) { + if(typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + var raw = data; + if(data && data.nodeType == 9) { + data = data.documentElement; + } + var capabilities = {}; + this.readNode(data, capabilities); + return capabilities; + }, + + /** + * 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: { + "wcs": { + "WCS_Capabilities": function(node, obj) { // In 1.0.0, this was WCS_Capabilties, changed in 1.1.0 + this.readChildNodes(node, obj); + }, + "Name": function(node, obj) { //???? + var name = this.getChildValue(node); + if(name) { + var parts = name.split(":"); + obj.name = parts.pop(); + if(parts.length > 0) { + obj.featureNS = this.lookupNamespaceURI(node, parts[0]); + } + } + }, + "Title": function(node, obj) { + var title = this.getChildValue(node); + if(title) { + obj.title = title; + } + }, + "Abstract": function(node, obj) { + var abst = this.getChildValue(node); + if(abst) { + obj["abstract"] = abst; + } + } + } + }, + + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1" + +}); \ No newline at end of file diff --git a/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js b/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js new file mode 100644 index 0000000000..e5d0803b62 --- /dev/null +++ b/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js @@ -0,0 +1,115 @@ +/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Format/WCSCapabilities/v1.js + */ + +/** + * Class: OpenLayers.Format.WCSCapabilities/v1_0_0 + * Read WCS Capabilities version 1.0.0. + * + * Inherits from: + * - + */ +OpenLayers.Format.WCSCapabilities.v1_0_0 = OpenLayers.Class( + OpenLayers.Format.WCSCapabilities.v1, { + + /** + * Constructor: OpenLayers.Format.WCSCapabilities.v1_0_0 + * Create a new parser for WCS capabilities version 1.0.0. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * 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: { + "wcs": OpenLayers.Util.applyDefaults({ + "Service": function(node, capabilities) { + capabilities.service = {}; + this.readChildNodes(node, capabilities.service); + }, + "Fees": function(node, service) { + var fees = this.getChildValue(node); + if (fees && fees.toLowerCase() != "none") { + service.fees = fees; + } + }, + "AccessConstraints": function(node, service) { + var constraints = this.getChildValue(node); + if (constraints && constraints.toLowerCase() != "none") { + service.accessConstraints = constraints; + } + }, + "OnlineResource": function(node, service) { + var onlineResource = this.getChildValue(node); + if (onlineResource && onlineResource.toLowerCase() != "none") { + service.onlineResource = onlineResource; + } + }, + "Keywords": function(node, service) { + var keywords = this.getChildValue(node); + if (keywords && keywords.toLowerCase() != "none") { + service.keywords = keywords.split(', '); + } + }, + "Capability": function(node, capabilities) { + capabilities.capability = {}; + this.readChildNodes(node, capabilities.capability); + }, + "Request": function(node, obj) { + obj.request = {}; + this.readChildNodes(node, obj.request); + }, + "GetFeature": function(node, request) { + request.getfeature = { + href: {}, // DCPType + formats: [] // ResultFormat + }; + this.readChildNodes(node, request.getfeature); + }, + "ResultFormat": function(node, obj) { + var children = node.childNodes; + var childNode; + for(var i=0; i + */ +OpenLayers.Format.WCSCapabilities.v1_1_0 = OpenLayers.Class( + OpenLayers.Format.WCSCapabilities.v1, { + + /** + * Property: regExes + * Compiled regular expressions for manipulating strings. + */ + regExes: { + trimSpace: (/^\s*|\s*$/g), + removeSpace: (/\s*/g), + splitSpace: (/\s+/), + trimComma: (/\s*,\s*/g) + }, + + + errorProperty: "Contents", // <== Not sure if this is strictly required by standard... maybe better to set to NULL? + + + /** + * Constructor: OpenLayers.Format.WCSCapabilities.v1_1_0 + * Create a new parser for WCS capabilities version 1.1.0. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + + /** + * 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: { + "wcs": OpenLayers.Util.applyDefaults({ + "Capabilities": function(node, obj) { // In 1.0.0, this was WCS_Capabilties, in 1.1.0, it's just Capabilities + this.readChildNodes(node, obj); + }, + + "Contents": function(node, request) { + request.featureTypeList = { + contents: [] + }; + this.readChildNodes(node, request.contents); + }, + + "CoverageSummary": function(node, request) { + request.featureTypeList = { + coverageSummary: [] + }; + this.readChildNodes(node, request.coverageSummary); + }, + + "Identifier": function(node, obj) { + obj.identifier = this.getChildValue(node); + }, + + "SupportedCRS": function(node, obj) { + var crs = this.getChildValue(node); + if(crs) { + if(!obj["supportedCRS"]) { + obj["supportedCRS"] = []; + } + obj["supportedCRS"].push(crs); + } + }, + + "DefaultSRS": function(node, obj) { + var defaultSRS = this.getChildValue(node); + if (defaultSRS) { + obj.srs = defaultSRS; + } + } + }, OpenLayers.Format.WCSCapabilities.v1.prototype.readers["wcs"]), + "ows": OpenLayers.Format.OWSCommon.v1.prototype.readers["ows"] + }, + + CLASS_NAME: "OpenLayers.Format.WCSCapabilities.v1_1_0" + +}); \ No newline at end of file diff --git a/lib/OpenLayers/Protocol/WCS.js b/lib/OpenLayers/Protocol/WCS.js new file mode 100644 index 0000000000..9520e3fbc0 --- /dev/null +++ b/lib/OpenLayers/Protocol/WCS.js @@ -0,0 +1,86 @@ +/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Protocol.js + */ + +/** + * Class: OpenLayers.Protocol.WCS + * Used to create a versioned WCS protocol. Default version is 1.0.0. + * + * Returns: + * {} A WCS protocol of the given version. + * + * Example: + * (code) + * var protocol = new OpenLayers.Protocol.WCS({ + * version: "1.1.0", + * url: "http://demo.opengeo.org/geoserver/wcs", + * featureType: "tasmania_roads", + * featureNS: "http://www.openplans.org/topp", + * geometryName: "the_geom" + * }); + * (end) + * + * See the protocols for specific WCS versions for more detail. + */ +OpenLayers.Protocol.WCS = function(options) { + options = OpenLayers.Util.applyDefaults( + options, OpenLayers.Protocol.WCS.DEFAULTS + ); + var cls = OpenLayers.Protocol.WCS["v"+options.version.replace(/\./g, "_")]; + if(!cls) { + throw "Unsupported WCS version: " + options.version; + } + return new cls(options); +}; + +/** + * Function: fromWMSLayer + * Convenience function to create a WCS protocol from a WMS layer. This makes + * the assumption that a WCS requests can be issued at the same URL as + * WMS requests and that a WCS featureType exists with the same name as the + * WMS layer. + * + * This function is designed to auto-configure , , + * and for WCS 1.1.0. Note that + * srsName matching with the WMS layer will not work with WCS 1.0.0. + * + * Parameters: + * layer - {} WMS layer that has a matching WCS + * FeatureType at the same server url with the same typename. + * options - {Object} Default properties to be set on the protocol. + * + * Returns: + * {} + */ +OpenLayers.Protocol.WCS.fromWMSLayer = function(layer, options) { + var typeName, featurePrefix; + var param = layer.params["LAYERS"]; + var parts = (OpenLayers.Util.isArray(param) ? param[0] : param).split(":"); + if(parts.length > 1) { + featurePrefix = parts[0]; + } + typeName = parts.pop(); + var protocolOptions = { + url: layer.url, + featureType: typeName, + featurePrefix: featurePrefix, + srsName: layer.projection && layer.projection.getCode() || + layer.map && layer.map.getProjectionObject().getCode(), + version: "1.1.0" + }; + return new OpenLayers.Protocol.WCS(OpenLayers.Util.applyDefaults( + options, protocolOptions + )); +}; + +/** + * Constant: OpenLayers.Protocol.WCS.DEFAULTS + */ +OpenLayers.Protocol.WCS.DEFAULTS = { + "version": "1.0.0" +}; \ No newline at end of file diff --git a/lib/OpenLayers/Protocol/WCS/v1.js b/lib/OpenLayers/Protocol/WCS/v1.js new file mode 100644 index 0000000000..894918461b --- /dev/null +++ b/lib/OpenLayers/Protocol/WCS/v1.js @@ -0,0 +1,434 @@ +/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Protocol/WCS.js + */ + +/** + * Class: OpenLayers.Protocol.WCS.v1 + * Abstract class for for v1.0.0 and v1.1.0 protocol. + * + * Inherits from: + * - + */ +OpenLayers.Protocol.WCS.v1 = OpenLayers.Class(OpenLayers.Protocol, { + + /** + * Property: version + * {String} WCS version number. + */ + version: null, + + /** + * Property: srsName + * {String} Name of spatial reference system. Default is "EPSG:4326". + */ + srsName: "EPSG:4326", + + /** + * Property: featureType + * {String} Local feature typeName. + */ + featureType: null, + + /** + * Property: featureNS + * {String} Feature namespace. + */ + featureNS: null, + + /** + * Property: geometryName + * {String} Name of the geometry attribute for features. Default is + * "the_geom" for WCS 1.0, and null for higher versions. + */ + geometryName: "the_geom", + + /** + * Property: schema + * {String} Optional schema location that will be included in the + * schemaLocation attribute value. Note that the feature type schema + * is required for a strict XML validator (on transactions with an + * insert for example), but is *not* required by the WCS specification + * (since the server is supposed to know about feature type schemas). + */ + schema: null, + + /** + * Property: featurePrefix + * {String} Namespace alias for feature type. Default is "feature". + */ + featurePrefix: "feature", + + /** + * Property: formatOptions + * {Object} Optional options for the format. If a format is not provided, + * this property can be used to extend the default format options. + */ + formatOptions: null, + + /** + * Property: readFormat + */ + readFormat: null, + + /** + * Property: readOptions + * {Object} Optional object to pass to format's read. + */ + readOptions: null, + + /** + * Constructor: OpenLayers.Protocol.WCS + * A class for giving layers WCS protocol. + * + * Parameters: + * options - {Object} Optional object whose properties will be set on the + * instance. + * + * Valid options properties: + * url - {String} URL to send requests to (required). + * featureType - {String} Local (without prefix) feature typeName (required). + * featureNS - {String} Feature namespace (required, but can be autodetected + * during the first query if GML is used as readFormat and + * featurePrefix is provided and matches the prefix used by the server + * for this featureType). + * featurePrefix - {String} Feature namespace alias (optional - only used + * for writing if featureNS is provided). Default is 'feature'. + * geometryName - {String} Name of geometry attribute. The default is + * 'the_geom' for WCS 1.0, and null for higher versions. If + * null, it will be set to the name of the first geometry found in the + * first read operation. + * multi - {Boolean} If set to true, geometries will be casted to Multi + * geometries before they are written in a transaction. No casting will + * be done when reading features. + */ + initialize: function(options) { + OpenLayers.Protocol.prototype.initialize.apply(this, [options]); + + if (!options.geometryName && parseFloat(this.format.version) > 1.0) { + this.setGeometryName(null); + } + }, + + /** + * APIMethod: destroy + * Clean up the protocol. + */ + destroy: function() { + if(this.options && !this.options.format) { + this.format.destroy(); + } + this.format = null; + OpenLayers.Protocol.prototype.destroy.apply(this); + }, + + /** + * APIMethod: read + * Construct a request for reading new features. Since WCS splits the + * basic CRUD operations into GetFeature requests (for read) and + * Transactions (for all others), this method does not make use of the + * format's read method (that is only about reading transaction + * responses). + * + * Parameters: + * options - {Object} Options for the read operation, in addition to the + * options set on the instance (options set here will take precedence). + * + * To use a configured protocol to get e.g. a WCS hit count, applications + * could do the following: + * + * (code) + * protocol.read({ + * readOptions: {output: "object"}, + * resultType: "hits", + * maxFeatures: null, + * callback: function(resp) { + * // process resp.numberOfFeatures here + * } + * }); + * (end) + * + * To use a configured protocol to use WCS paging (if supported by the + * server), applications could do the following: + * + * (code) + * protocol.read({ + * startIndex: 0, + * count: 50 + * }); + * (end) + * + * To limit the attributes returned by the GetFeature request, applications + * can use the propertyNames option to specify the properties to include in + * the response: + * + * (code) + * protocol.read({ + * propertyNames: ["DURATION", "INTENSITY"] + * }); + * (end) + */ + read: function(options) { + OpenLayers.Protocol.prototype.read.apply(this, arguments); + options = OpenLayers.Util.extend({}, options); + OpenLayers.Util.applyDefaults(options, this.options || {}); + var response = new OpenLayers.Protocol.Response({requestType: "read"}); + + var data = OpenLayers.Format.XML.prototype.write.apply( + this.format, [this.format.writeNode("wcs:GetFeature", options)] + ); + + response.priv = OpenLayers.Request.POST({ + url: options.url, + callback: this.createCallback(this.handleRead, response, options), + params: options.params, + headers: options.headers, + data: data + }); + + return response; + }, + + /** + * APIMethod: setFeatureType + * Change the feature type on the fly. + * + * Parameters: + * featureType - {String} Local (without prefix) feature typeName. + */ + setFeatureType: function(featureType) { + this.featureType = featureType; + this.format.featureType = featureType; + }, + + /** + * APIMethod: setGeometryName + * Sets the geometryName option after instantiation. + * + * Parameters: + * geometryName - {String} Name of geometry attribute. + */ + setGeometryName: function(geometryName) { + this.geometryName = geometryName; + this.format.geometryName = geometryName; + }, + + /** + * Method: handleRead + * Deal with response from the read request. + * + * Parameters: + * response - {} The response object to pass + * to the user callback. + * options - {Object} The user options passed to the read call. + */ + handleRead: function(response, options) { + options = OpenLayers.Util.extend({}, options); + OpenLayers.Util.applyDefaults(options, this.options); + + if(options.callback) { + var request = response.priv; + if(request.status >= 200 && request.status < 300) { + // success + var result = this.parseResponse(request, options.readOptions); + if (result && result.success !== false) { + if (options.readOptions && options.readOptions.output == "object") { + OpenLayers.Util.extend(response, result); + } else { + response.features = result; + } + response.code = OpenLayers.Protocol.Response.SUCCESS; + } else { + // failure (service exception) + response.code = OpenLayers.Protocol.Response.FAILURE; + response.error = result; + } + } else { + // failure + response.code = OpenLayers.Protocol.Response.FAILURE; + } + options.callback.call(options.scope, response); + } + }, + + /** + * Method: parseResponse + * Read HTTP response body and return features + * + * Parameters: + * request - {XMLHttpRequest} The request object + * options - {Object} Optional object to pass to format's read + * + * Returns: + * {Object} or {Array({})} or + * {} + * An object with a features property, an array of features or a single + * feature. + */ + parseResponse: function(request, options) { + var doc = request.responseXML; + if(!doc || !doc.documentElement) { + doc = request.responseText; + } + if(!doc || doc.length <= 0) { + return null; + } + var result = (this.readFormat !== null) ? this.readFormat.read(doc) : + this.format.read(doc, options); + if (!this.featureNS) { + var format = this.readFormat || this.format; + this.featureNS = format.featureNS; + // no need to auto-configure again on subsequent reads + format.autoConfig = false; + if (!this.geometryName) { + this.setGeometryName(format.geometryName); + } + } + return result; + }, + + /** + * Method: commit + * Given a list of feature, assemble a batch request for update, create, + * and delete transactions. A commit call on the prototype amounts + * to writing a WCS transaction - so the write method on the format + * is used. + * + * Parameters: + * features - {Array()} + * options - {Object} + * + * Valid options properties: + * nativeElements - {Array({Object})} Array of objects with information for writing + * out elements, these objects have vendorId, safeToIgnore and + * value properties. The element is intended to allow access to + * vendor specific capabilities of any particular web feature server or + * datastore. + * + * Returns: + * {} A response object with a features + * property containing any insertIds and a priv property referencing + * the XMLHttpRequest object. + */ + commit: function(features, options) { + + options = OpenLayers.Util.extend({}, options); + OpenLayers.Util.applyDefaults(options, this.options); + + var response = new OpenLayers.Protocol.Response({ + requestType: "commit", + reqFeatures: features + }); + response.priv = OpenLayers.Request.POST({ + url: options.url, + headers: options.headers, + data: this.format.write(features, options), + callback: this.createCallback(this.handleCommit, response, options) + }); + + return response; + }, + + /** + * Method: handleCommit + * Called when the commit request returns. + * + * Parameters: + * response - {} The response object to pass + * to the user callback. + * options - {Object} The user options passed to the commit call. + */ + handleCommit: function(response, options) { + if(options.callback) { + var request = response.priv; + + // ensure that we have an xml doc + var data = request.responseXML; + if(!data || !data.documentElement) { + data = request.responseText; + } + + var obj = this.format.read(data) || {}; + + response.insertIds = obj.insertIds || []; + if (obj.success) { + response.code = OpenLayers.Protocol.Response.SUCCESS; + } else { + response.code = OpenLayers.Protocol.Response.FAILURE; + response.error = obj; + } + options.callback.call(options.scope, response); + } + }, + + /** + * Method: filterDelete + * Send a request that deletes all features by their filter. + * + * Parameters: + * filter - {} filter + */ + filterDelete: function(filter, options) { + options = OpenLayers.Util.extend({}, options); + OpenLayers.Util.applyDefaults(options, this.options); + + var response = new OpenLayers.Protocol.Response({ + requestType: "commit" + }); + + var root = this.format.createElementNSPlus("wcs:Transaction", { + attributes: { + service: "WCS", + version: this.version + } + }); + + var deleteNode = this.format.createElementNSPlus("wcs:Delete", { + attributes: { + typeName: (options.featureNS ? this.featurePrefix + ":" : "") + + options.featureType + } + }); + + if(options.featureNS) { + deleteNode.setAttribute("xmlns:" + this.featurePrefix, options.featureNS); + } + var filterNode = this.format.writeNode("ogc:Filter", filter); + + deleteNode.appendChild(filterNode); + + root.appendChild(deleteNode); + + var data = OpenLayers.Format.XML.prototype.write.apply( + this.format, [root] + ); + + return OpenLayers.Request.POST({ + url: this.url, + callback : options.callback || function(){}, + data: data + }); + + }, + + /** + * Method: abort + * Abort an ongoing request, the response object passed to + * this method must come from this protocol (as a result + * of a read, or commit operation). + * + * Parameters: + * response - {} + */ + abort: function(response) { + if (response) { + response.priv.abort(); + } + }, + + CLASS_NAME: "OpenLayers.Protocol.WCS.v1" +}); diff --git a/lib/OpenLayers/Protocol/WCS/v1_0_0.js b/lib/OpenLayers/Protocol/WCS/v1_0_0.js new file mode 100644 index 0000000000..54a5b8b3a2 --- /dev/null +++ b/lib/OpenLayers/Protocol/WCS/v1_0_0.js @@ -0,0 +1,43 @@ +/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Protocol/WCS/v1.js + */ + +/** + * Class: OpenLayers.Protocol.WCS.v1_0_0 + * A WCS v1.0.0 protocol for vector layers. Create a new instance with the + * constructor. + * + * Inherits from: + * - + */ +OpenLayers.Protocol.WCS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol.WCS.v1, { + + /** + * Property: version + * {String} WCS version number. + */ + version: "1.0.0", + + /** + * Constructor: OpenLayers.Protocol.WCS.v1_0_0 + * A class for giving layers WCS v1.0.0 protocol. + * + * Parameters: + * options - {Object} Optional object whose properties will be set on the + * instance. + * + * Valid options properties: + * featureType - {String} Local (without prefix) feature typeName (required). + * featureNS - {String} Feature namespace (optional). + * featurePrefix - {String} Feature namespace alias (optional - only used + * if featureNS is provided). Default is 'feature'. + * geometryName - {String} Name of geometry attribute. Default is 'the_geom'. + */ + + CLASS_NAME: "OpenLayers.Protocol.WCS.v1_0_0" +}); \ No newline at end of file diff --git a/lib/OpenLayers/Protocol/WCS/v1_1_0.js b/lib/OpenLayers/Protocol/WCS/v1_1_0.js new file mode 100644 index 0000000000..05b86f11e8 --- /dev/null +++ b/lib/OpenLayers/Protocol/WCS/v1_1_0.js @@ -0,0 +1,37 @@ +/* ====================================================================== + OpenLayers/Protocol/WCS/v1_1_0.js + ====================================================================== */ + +/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + +/** + * @requires OpenLayers/Protocol/WCS/v1.js + */ + +/** + * Class: OpenLayers.Protocol.WCS.v1_1_0 + * A WCS v1.1.0 protocol for vector layers. Create a new instance with the + * constructor. + * + * Differences from the v1.0.0 protocol: + * - uses Filter Encoding 1.1.0 instead of 1.0.0 + * - uses GML 3 instead of 2 if no format is provided + * + * Inherits from: + * - + */ +OpenLayers.Protocol.WCS.v1_1_0 = OpenLayers.Class(OpenLayers.Protocol.WCS.v1, { + + /** + * Property: version + * {String} WCS version number. + */ + version: "1.1.0", + + + + CLASS_NAME: "OpenLayers.Protocol.WCS.v1_1_0" +}); diff --git a/tests/Format/WCSCapabilities.html b/tests/Format/WCSCapabilities.html new file mode 100644 index 0000000000..aa3d3267ae --- /dev/null +++ b/tests/Format/WCSCapabilities.html @@ -0,0 +1,43 @@ + + + + + + + + \ No newline at end of file diff --git a/tests/Format/WCSCapabilities/v1.html b/tests/Format/WCSCapabilities/v1.html new file mode 100644 index 0000000000..ea4dd1129c --- /dev/null +++ b/tests/Format/WCSCapabilities/v1.html @@ -0,0 +1,181 @@ + + + + + + + + From d0986de775c114ea040ac5fc31a285466fe2b854 Mon Sep 17 00:00:00 2001 From: Christopher Eykamp Date: Fri, 21 Dec 2012 18:51:39 +0100 Subject: [PATCH 027/123] WCS 1.0.0 parsing now passing all tests --- lib/OpenLayers/Format/WCSCapabilities/v1.js | 15 +- .../Format/WCSCapabilities/v1_0_0.js | 167 +++++++++++++----- tests/Format/WCSCapabilities/v1.html | 39 ++-- 3 files changed, 157 insertions(+), 64 deletions(-) diff --git a/lib/OpenLayers/Format/WCSCapabilities/v1.js b/lib/OpenLayers/Format/WCSCapabilities/v1.js index 47aa0b9411..54d2f3e0b7 100644 --- a/lib/OpenLayers/Format/WCSCapabilities/v1.js +++ b/lib/OpenLayers/Format/WCSCapabilities/v1.js @@ -28,6 +28,11 @@ OpenLayers.Format.WCSCapabilities.v1 = OpenLayers.Class( ows: "http://www.opengis.net/ows" }, + regExes: { + trimSpace: (/^\s*|\s*$/g), + splitSpace: (/\s+/) + }, + /** * Property: defaultPrefix */ @@ -78,16 +83,6 @@ OpenLayers.Format.WCSCapabilities.v1 = OpenLayers.Class( "WCS_Capabilities": function(node, obj) { // In 1.0.0, this was WCS_Capabilties, changed in 1.1.0 this.readChildNodes(node, obj); }, - "Name": function(node, obj) { //???? - var name = this.getChildValue(node); - if(name) { - var parts = name.split(":"); - obj.name = parts.pop(); - if(parts.length > 0) { - obj.featureNS = this.lookupNamespaceURI(node, parts[0]); - } - } - }, "Title": function(node, obj) { var title = this.getChildValue(node); if(title) { diff --git a/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js b/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js index e5d0803b62..d175f2a9f3 100644 --- a/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js +++ b/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js @@ -36,59 +36,142 @@ OpenLayers.Format.WCSCapabilities.v1_0_0 = OpenLayers.Class( */ readers: { "wcs": OpenLayers.Util.applyDefaults({ - "Service": function(node, capabilities) { - capabilities.service = {}; - this.readChildNodes(node, capabilities.service); + "Service": function(node, obj) { + obj.service = {}; + this.readChildNodes(node, obj.service); }, - "Fees": function(node, service) { - var fees = this.getChildValue(node); - if (fees && fees.toLowerCase() != "none") { - service.fees = fees; - } + "name": function(node, service) { + service.name = this.getChildValue(node); }, - "AccessConstraints": function(node, service) { - var constraints = this.getChildValue(node); - if (constraints && constraints.toLowerCase() != "none") { - service.accessConstraints = constraints; - } + "label": function(node, service) { + service.label = this.getChildValue(node); }, - "OnlineResource": function(node, service) { - var onlineResource = this.getChildValue(node); - if (onlineResource && onlineResource.toLowerCase() != "none") { - service.onlineResource = onlineResource; - } + "keywords": function(node, service) { + service.keywords = []; + this.readChildNodes(node, service.keywords); }, - "Keywords": function(node, service) { - var keywords = this.getChildValue(node); - if (keywords && keywords.toLowerCase() != "none") { - service.keywords = keywords.split(', '); - } + "keyword": function(node, keywords) { + keywords.push(this.getChildValue(node)); // Append the keyword to the keywords list }, - "Capability": function(node, capabilities) { - capabilities.capability = {}; - this.readChildNodes(node, capabilities.capability); + "responsibleParty": function(node, service) { + service.responsibleParty = {}; + this.readChildNodes(node, service.responsibleParty); }, - "Request": function(node, obj) { - obj.request = {}; - this.readChildNodes(node, obj.request); + "individualName": function(node, responsibleParty) { + responsibleParty.individualName = this.getChildValue(node); }, - "GetFeature": function(node, request) { - request.getfeature = { - href: {}, // DCPType - formats: [] // ResultFormat - }; - this.readChildNodes(node, request.getfeature); + "organisationName": function(node, responsibleParty) { + responsibleParty.organisationName = this.getChildValue(node); }, - "ResultFormat": function(node, obj) { - var children = node.childNodes; - var childNode; - for(var i=0; i. Only write the data if everything parsed neatly. + // This works well for the data samples I have access to, but may need to be generalized to cover other possible use cases. + var nodeList = this.getElementsByTagNameNS(node, "http://www.opengis.net/gml", "pos"); + + // We expect two nodes here, to create the corners of a bounding box + if(nodeList.length == 2) { + var min = {}, + max = {}; + + var ok = true; + + // min + var coordString = nodeList[0].firstChild.nodeValue; + + coordString = coordString.replace(this.regExes.trimSpace, ""); + var coords = coordString.split(this.regExes.splitSpace); + + if(coords.length == 2) { + min.lon = coords[0]; + min.lat = coords[1]; + } else { + ok = false; + } + + // max + var coordString = nodeList[1].firstChild.nodeValue; + + coordString = coordString.replace(this.regExes.trimSpace, ""); + var coords = coordString.split(this.regExes.splitSpace); + + if(coords.length == 2) { + max.lon = coords[0]; + max.lat = coords[1]; + } else { + ok = false; + } + + if(ok) { + coverageOfferingBrief.lonLatEnvelope = {}; + coverageOfferingBrief.lonLatEnvelope.srsName = node.getAttribute("srsName"); + coverageOfferingBrief.lonLatEnvelope.min = min; + coverageOfferingBrief.lonLatEnvelope.max = max; } } + }, + + //////////////////////////////////////////////////////////////////////////////////////////// + + "DCPType": function(node, obj) { this.readChildNodes(node, obj); }, diff --git a/tests/Format/WCSCapabilities/v1.html b/tests/Format/WCSCapabilities/v1.html index ea4dd1129c..24bc5ec2d7 100644 --- a/tests/Format/WCSCapabilities/v1.html +++ b/tests/Format/WCSCapabilities/v1.html @@ -21,26 +21,41 @@ } function test_read(t) { - t.plan(37); // Number of tests performed: If you add a test below, be sure to increment this accordingly + t.plan(25); // Number of tests performed: If you add a test below, be sure to increment this accordingly var parser = new OpenLayers.Format.WCSCapabilities(); // GeoServer, v1.0.0 - var text = 'MapServer WCSGeospatial WebServicesLuxembourg!Franko LemmerCRP Henri TudorR+D engineer00352 4321 234500352 43210 123
    128, rue de LuxembourgEsch-sur-Alzette4221Luxembourgfranko.lemmer@flensburger.de
    nonenone
    application/vnd.ogc.se_xmlro_dsm4.44444 51.5151515.55555 52.525252ro_dsm_mini4.47489346945755 51.91594537869274.47687824892444 51.9170706688033ro_irra4.471333734139 51.9128134273834.4808508475645 51.9248713705576ro_irra_ext4.10024171314823 51.93597649928444.21909054278063 52.001415228243
    '; + var text = 'MapServer WCSGeospatial WebServicesLuxembourg!Franko LemmerCRP Henri TudorR+D engineer64633206465955
    66, rue de LuxembourgEsch-sur-Alzette97202Luxembourgfranko.lemmer@flensburger.de
    mucho dineroOpen to the public
    application/vnd.ogc.se_xmlro_dsm4.44444 51.5151515.55555 52.525252ro_dsm_mini4.47489346945755 51.91594537869274.47687824892444 51.9170706688033ro_irra4.471333734139 51.9128134273834.4808508475645 51.9248713705576ro_irra_ext4.10024171314823 51.93597649928444.21909054278063 52.001415228243
    '; -debugger; var res = parser.read(text); t.ok(!res.error, "Parsing XML generated no errors"); - t.eq(res.operationsMetadata["GetFeature"].dcp.http.get[0].url, "http://services.magnificent.get.lu/cgi-bin/mapserv?", "GetFeature GET endpoint correctly parsed"); - t.eq(res.operationsMetadata["GetFeature"].dcp.http.post[0].url, "http://services.magnificent.post.lu/cgi-bin/mapserv?", "GetFeature POST endpoint correctly parsed"); - var ft = res.featureTypeList.featureTypes; - t.eq(ft.length, 4, "number of feature types correct"); - t.eq(ft[0]["label"], "Rotterdam DSM", "label of first feature type correct"); - t.eq(ft[0]["name"], "ro_dsm", "name of first feature type correct"); - t.eq(ft[0]["featureNS"], "http://www.census.gov", "ns of first feature type correct"); - t.eq(ft[0]["srs"], "urn:ogc:def:crs:OGC:1.3:CRS84", "srs of first feature type correct"); - t.eq(ft[0]["title"], "Manhattan (NY) landmarks", "title of first feature type correct"); + t.eq(res.service.fees, "mucho dinero", "Service>Fees correctly parsed"); + t.eq(res.service.accessConstraints, "Open to the public", "Service>AccessConstraints correctly parsed"); + t.eq(res.service.keywords.length, 2, "Correct number of Service>Keywords found"); + t.eq(res.service.keywords[0], "Geospatial WebServices", "Service>Keywords correctly parsed"); + t.eq(res.service.label, "WCS Sample Data Server 1.0.0", "Service>Label correctly parsed"); + t.eq(res.service.name, "MapServer WCS", "Service>Name correctly parsed"); + t.eq(res.service.responsibleParty.individualName, "Franko Lemmer", "Service>ResponsibleParty>IndividualName correctly parsed"); + t.eq(res.service.responsibleParty.organisationName, "CRP Henri Tudor", "Service>ResponsibleParty>OrganisationName correctly parsed"); + t.eq(res.service.responsibleParty.positionName, "R+D engineer", "Service>ResponsibleParty>PositionName correctly parsed"); + t.eq(res.service.responsibleParty.contactInfo.address.city, "Esch-sur-Alzette", "Service>responsibleParty>ContactInfo>Address>City correctly parsed"); + t.eq(res.service.responsibleParty.contactInfo.address.country, "Luxembourg", "Service>responsibleParty>ContactInfo>Address>Country correctly parsed"); + t.eq(res.service.responsibleParty.contactInfo.address.deliveryPoint, "66, rue de Luxembourg", "Service>responsibleParty>ContactInfo>Address>DeliveryPoint correctly parsed"); + t.eq(res.service.responsibleParty.contactInfo.address.electronicMailAddress, "franko.lemmer@flensburger.de", "Service>responsibleParty>ContactInfo>Address>ElectronicMailAddress correctly parsed"); + t.eq(res.service.responsibleParty.contactInfo.address.postalCode, "97202", "Service>responsibleParty>ContactInfo>Address>PostalCode correctly parsed"); + t.eq(res.service.responsibleParty.contactInfo.phone.facsimile, "6465955", "Service>responsibleParty>ContactInfo>Phone>Facsimile correctly parsed"); + t.eq(res.service.responsibleParty.contactInfo.phone.voice, "6463320", "Service>responsibleParty>ContactInfo>Phone>Voice correctly parsed"); + t.eq(res.contentMetadata.length, 4, "Correct number of metadata records found"); + t.eq(res.contentMetadata[0].label, "Rotterdam DSM", "ContentMetadata>Label correctly parsed"); + t.eq(res.contentMetadata[0].lonLatEnvelope.min.lat, "51.515151", "ContentMetadata>lonLatEnvelope>Min>Lat correctly parsed"); + t.eq(res.contentMetadata[0].lonLatEnvelope.min.lon, "4.44444", "ContentMetadata>lonLatEnvelope>Min>Lon correctly parsed"); + t.eq(res.contentMetadata[0].lonLatEnvelope.max.lat, "52.525252", "ContentMetadata>lonLatEnvelope>Max>Lat correctly parsed"); + t.eq(res.contentMetadata[0].lonLatEnvelope.max.lon, "5.55555", "ContentMetadata>lonLatEnvelope>Max>Lon correctly parsed"); + t.eq(res.contentMetadata[0].lonLatEnvelope.srsName, "urn:ogc:def:crs:OGC:1.3:CRS84", "ContentMetadata>lonLatEnvelope>SrsName correctly parsed"); + t.eq(res.contentMetadata[0].name, "ro_dsm", "ContentMetadata>Name correctly parsed"); + // // GeoServer, v1.0.0 // text = 'WFSGeoServer Web Feature ServiceThis is the reference implementation of WFS 1.0.0 and WFS 1.1.0, supports all WFS operations including Transaction.WFS, WMS, GEOSERVERhttp://localhost:80/geoserver/wfsNONENONEtiger:poly_landmarksManhattan (NY) landmarksManhattan landmarks, identifies water, lakes, parks, interesting buildilngsDS_poly_landmarks, poly_landmarks, landmarks, manhattanEPSG:4326tiger:poiManhattan (NY) points of interestPoints of interest in New York, New York (on Manhattan). One of the attributes contains the name of a file with a picture of the point of interest.poi, DS_poi, points_of_interest, ManhattanEPSG:4326tiger:tiger_roadsManhattan (NY) roadsHighly simplified road layout of Manhattan in New York..DS_tiger_roads, tiger_roads, roadsEPSG:4326sf:archsitesSpearfish archeological sitesSample data from GRASS, archeological sites location, Spearfish, South Dakota, USAarchsites, sfArchsites, spearfish, archeologyEPSG:26713sf:bugsitesSpearfish bug locationsSample data from GRASS, bug sites location, Spearfish, South Dakota, USAsfBugsites, bugsites, insects, spearfish, tiger_beetlesEPSG:26713sf:restrictedSpearfish restricted areasSample data from GRASS, restricted areas, Spearfish, South Dakota, USArestricted, sfRestricted, spearfish, areasEPSG:26713sf:roadsSpearfish roadsSample data from GRASS, road layout, Spearfish, South Dakota, USAsfRoads, roads, spearfishEPSG:26713sf:streamsSpearfish streamsSample data from GRASS, streams, Spearfish, South Dakota, USAsfStreams, streams, spearfishEPSG:26713topp:tasmania_citiesTasmania citiesCities in Tasmania (actually, just the capital)cities, TasmaniaEPSG:4326topp:tasmania_roadsTasmania roadsMain Tasmania roadsRoads, TasmaniaEPSG:4326topp:tasmania_state_boundariesTasmania state boundariesTasmania state boundariestasmania_state_boundaries, Tasmania, boundariesEPSG:4326topp:tasmania_water_bodiesTasmania water bodiesTasmania water bodiesLakes, Bodies, Australia, Water, TasmaniaEPSG:4326topp:statesUSA PopulationThis is some census data on the states.census, united, boundaries, state, statesEPSG:4326tiger:giant_polygonWorld rectangleA simple rectangular polygon covering most of the world, it\'s only used for the purpose of providing a background (WMS bgcolor could be used instead)DS_giant_polygon, giant_polygonEPSG:4326absabs_2abs_3abs_4acosAreaasinatanatan2betweenboundaryboundaryDimensionbufferbufferWithSegmentsceilcentroidclassifyCollection_AverageCollection_BoundsCollection_CountCollection_MaxCollection_MedianCollection_MinCollection_SumCollection_UniqueConcatenatecontainsconvexHullcoscrossesdateFormatdateParsedifferencedimensiondisjointdistancedouble2boolendPointenvelopeEqualIntervalequalsExactequalsExactToleranceequalToexpexteriorRingfloorgeometryTypegeomFromWKTgeomLengthgetGeometryNgetXgetYgetZgreaterEqualThangreaterThanidIEEEremainderif_then_elsein10in2in3in4in5in6in7in8in9int2bboolint2ddoubleinteriorPointinteriorRingNintersectionintersectsisClosedisEmptyisLikeisNullisRingisSimpleisValidisWithinDistancelengthlessEqualThanlessThanlogmaxmax_2max_3max_4minmin_2min_3min_4notnotEqualTonumGeometriesnumInteriorRingnumPointsoverlapsparseBooleanparseDoubleparseIntpipointNpowPropertyExistsQuantilerandomrelaterelatePatternrintroundround_2roundDoublesinsqrtStandardDeviationstartPointstrConcatstrEndsWithstrEqualsIgnoreCasestrIndexOfstrLastIndexOfstrLengthstrMatchesstrReplacestrStartsWithstrSubstringstrSubstringStartstrToLowerCasestrToUpperCasestrTrimsymDifferencetantoDegreestoRadianstouchestoWKTunionUniqueIntervalwithin'; From 9759902daccdf2fd919a9b7f495b5e3d320eb391 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Fri, 21 Dec 2012 21:24:04 +0100 Subject: [PATCH 028/123] Fixing API; addressing @mpriour's doc comment Previously, minFrameRate could not be set as option with the start method. The tests failed to catch this flaw. Now both the start method and the tests are fixed. --- lib/OpenLayers/Tween.js | 14 ++++++++------ tests/Tween.html | 31 +++++++++++++++++-------------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/lib/OpenLayers/Tween.js b/lib/OpenLayers/Tween.js index 14e77210b8..eb2ee94e9d 100644 --- a/lib/OpenLayers/Tween.js +++ b/lib/OpenLayers/Tween.js @@ -54,12 +54,12 @@ OpenLayers.Tween = OpenLayers.Class({ /** * APIProperty: minFrameRate - * {Number} The minimum framerate for animations. After each step, the time - * spent in the animation is compared to the calculated time at this frame - * rate. If the animation runs longer than the calculated time, the next - * step is skipped. + * {Number} The minimum framerate for animations in frames per second. After + * each step, the time spent in the animation is compared to the calculated + * time at this frame rate. If the animation runs longer than the calculated + * time, the next step is skipped. Default is 30. */ - minFrameRate: 30, + minFrameRate: null, /** * Property: startTime @@ -99,7 +99,8 @@ OpenLayers.Tween = OpenLayers.Class({ * begin - {Object} values to start the animation with * finish - {Object} values to finish the animation with * duration - {int} duration of the tween (number of steps) - * options - {Object} hash of options (for example callbacks (start, eachStep, done)) + * options - {Object} hash of options (callbacks (start, eachStep, done), + * minFrameRate) */ start: function(begin, finish, duration, options) { this.playing = true; @@ -107,6 +108,7 @@ OpenLayers.Tween = OpenLayers.Class({ this.finish = finish; this.duration = duration; this.callbacks = options.callbacks; + this.minFrameRate = options.minFrameRate || 30; this.time = 0; this.startTime = new Date().getTime(); OpenLayers.Animation.stop(this.animationId); diff --git a/tests/Tween.html b/tests/Tween.html index 5c52b84e26..1fbfa3cf1c 100644 --- a/tests/Tween.html +++ b/tests/Tween.html @@ -79,29 +79,32 @@ t.plan(2); var tween = new OpenLayers.Tween(); - var log1 = 0; + var log = 0; tween.start({count: 0}, {count: 10}, 10, { callbacks: { eachStep: function() { - log1++; + log++; } }, minFrameRate: 10000 }); - var log2 = 0; - tween.start({count: 0}, {count: 10}, 10, { - callbacks: { - eachStep: function() { - log2++; - } - }, - minFrameRate: 1 - }); - t.delay_call(0.8, function() { - t.eq(log1, 0, 'all frames skipped at a frame rate of 10000'); - t.eq(log2, 11, 'no frames skipped at a frame rate of 1'); + t.eq(log, 0, 'all frames skipped at a frame rate of 10000'); + + log = 0; + tween.start({count: 0}, {count: 10}, 10, { + callbacks: { + eachStep: function() { + log++; + } + }, + minFrameRate: 1 + }); + }); + + t.delay_call(1.6, function() { + t.eq(log, 11, 'no frames skipped at a frame rate of 1'); }); } From 2ee362a79bc38120b48ea69d65721019ecf73104 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Fri, 16 Nov 2012 16:19:59 +0100 Subject: [PATCH 029/123] New tile image cache and tile queue improvements We now reuse tile images by maintaining a cache of image elements with a simplified LRU expiry policy (by order, not by timestamp). The tile queue is bypassed for images that are available in the cache, so they can be rendered immediately. And the tile queue itself loads more than just one image at a time now (2 per layer url). --- lib/OpenLayers/Layer/Bing.js | 8 +-- lib/OpenLayers/Layer/Grid.js | 107 ++++++++++++++++++++++++++++------- tests/Layer/Grid.html | 33 +++++++++++ 3 files changed, 125 insertions(+), 23 deletions(-) diff --git a/lib/OpenLayers/Layer/Bing.js b/lib/OpenLayers/Layer/Bing.js index 638891dadb..06af556cf2 100644 --- a/lib/OpenLayers/Layer/Bing.js +++ b/lib/OpenLayers/Layer/Bing.js @@ -201,13 +201,13 @@ OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, { }, /** - * Method: drawTileFromQueue - * Draws the first tile from the tileQueue, and unqueues that tile + * Method: drawTilesFromQueue + * Draws tiles from the tileQueue, and unqueues the tiles */ - drawTileFromQueue: function() { + drawTilesFromQueue: function() { // don't start working on the queue before we have a url from initLayer if (this.url) { - OpenLayers.Layer.XYZ.prototype.drawTileFromQueue.apply(this, arguments); + OpenLayers.Layer.XYZ.prototype.drawTilesFromQueue.apply(this, arguments); } }, diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index 8791236cb6..28ae7734d5 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -144,7 +144,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { /** * Property: tileQueueId - * {Number} The id of the animation. + * {Number} The id of the animation. */ tileQueueId: null, @@ -240,6 +240,26 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { * should not be zero. */ className: null, + + /** + * Property: tileCache + * {Object} Cached image elements, keyed by URL. + */ + tileCache: null, + + /** + * Property: tileCacheIndex + * {Array} URLs of cached tiles; first entry is least recently + * used. + */ + tileCacheIndex: null, + + /** + * APIProperty: tileCacheSize + * {Number} Number of image elements to keep referenced for fast reuse. + * Default is 128 per layer. + */ + tileCacheSize: 128, /** * Register a listener for a particular event with the following syntax: @@ -309,6 +329,8 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { arguments); this.grid = []; this.tileQueue = []; + this.tileCache = {}; + this.tileCacheIndex = []; this._removeBackBuffer = OpenLayers.Function.bind(this.removeBackBuffer, this); if (this.removeBackBufferDelay === null) { @@ -370,6 +392,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { this.grid = null; this.tileSize = null; + this.tileCache = null; OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments); }, @@ -585,37 +608,79 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { */ queueTileDraw: function(evt) { var tile = evt.object; - if (!~OpenLayers.Util.indexOf(this.tileQueue, tile)) { - // queue only if not in queue already - this.tileQueue.push(tile); + var queued = false; + if (this.async || !this.url || + !this.tileCache[this.getURL(tile.bounds)]) { + // queue only if not in tileCache already + if (!~OpenLayers.Util.indexOf(this.tileQueue, tile)) { + // add to queue only if not in queue already + this.tileQueue.push(tile); + } + queued = true; + if (!this.tileQueueId) { + this.tileQueueId = OpenLayers.Animation.start( + OpenLayers.Function.bind(this.drawTilesFromQueue, this), + null, this.div + ); + } } - if (!this.tileQueueId) { - this.tileQueueId = OpenLayers.Animation.start( - OpenLayers.Function.bind(this.drawTileFromQueue, this), - null, this.div - ); - } - return false; + return !queued; }, /** - * Method: drawTileFromQueue - * Draws the first tile from the tileQueue, and unqueues that tile + * Method: drawTilesFromQueue + * Draws tiles from the tileQueue, and unqueues the tiles */ - drawTileFromQueue: function() { - if (this.tileQueue.length === 0) { - this.clearTileQueue(); - } else { + drawTilesFromQueue: function() { + var numUrls = OpenLayers.Util.isArray(this.url) ? this.url.length : 1; + //TODO instead of using 2 * urls, we could keep track of the hosts used + // by all grid layers, and use a number that just saturates the number + // of parallel requests the browser can send + while (this.numLoadingTiles < 2 * numUrls) { + if (this.tileQueue.length === 0) { + this.clearTileQueue(); + break; + } this.tileQueue.shift().draw(true); } }, + /** + * Method: manageTileCache + * Adds, updates, removes and fetches cache entries. + * + * Parameters: + * evt - {Object} Listener argument of the tile's loadstart event + */ + manageTileCache: function(evt) { + var tile = evt.object; + if (this.tileCache[tile.url]) { + tile.imgDiv = this.tileCache[tile.url]; + OpenLayers.Util.removeItem(this.tileCacheIndex, tile.url); + this.tileCacheIndex.push(tile.url); + tile.positionTile(); + this.div.appendChild(tile.imgDiv); + } else { + tile.events.register('loadend', this, function loadend() { + tile.events.unregister('loadend', this, loadend); + if (!this.tileCache[tile.url]) { + if (this.tileCacheIndex.length >= this.tileCacheSize) { + delete this.tileCache[this.tileCacheIndex[0]]; + this.tileCacheIndex.shift(); + } + this.tileCache[tile.url] = tile.imgDiv; + this.tileCacheIndex.push(tile.url); + } + }); + } + }, + /** * Method: clearTileQueue * Clears the animation queue */ clearTileQueue: function() { - OpenLayers.Animation.stop(this.tileQueueId); + window.clearInterval(this.tileQueueId); this.tileQueueId = null; this.tileQueue = []; }, @@ -1102,7 +1167,11 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { var tile = new this.tileClass( this, position, bounds, null, this.tileSize, this.tileOptions ); - tile.events.register("beforedraw", this, this.queueTileDraw); + tile.events.on({ + beforedraw: this.queueTileDraw, + loadstart: this.manageTileCache, + scope: this + }); return tile; }, diff --git a/tests/Layer/Grid.html b/tests/Layer/Grid.html index 6e7d4181bf..ac1db09e89 100644 --- a/tests/Layer/Grid.html +++ b/tests/Layer/Grid.html @@ -100,6 +100,39 @@ map.destroy(); } + function test_manageTileCache(t) { + t.plan(9); + + var map = new OpenLayers.Map('map'); + layer = new OpenLayers.Layer.WMS(name, "../../img/blank.gif", params, { + tileCacheSize: 12 + }); + map.addLayer(layer); + map.setCenter([16, 48], 9); + + var firstInCache, sharedTile; + t.delay_call(2, function() { + t.eq(layer.tileCacheIndex.length, 12, "tiles cached"); + t.ok(~OpenLayers.Util.indexOf(layer.tileCacheIndex, layer.grid[1][2].url), "tile found in cache"); + t.ok(layer.tileCache[layer.grid[1][2].url] === layer.grid[1][2].imgDiv, "correct object cached"); + firstInCache = layer.tileCache[layer.tileCacheIndex[0]]; + sharedTile = layer.tileCache[layer.tileCacheIndex[11]]; + map.setCenter([17, 47]); + }); + t.delay_call(4, function() { + t.eq(layer.tileCacheIndex.length, 12, "tiles cached"); + t.ok(layer.tileCache[layer.grid[1][2].url] === layer.grid[1][2].imgDiv, "correct object cached"); + t.ok(!(firstInCache.getAttribute("src") in layer.tileCache), "old tile discarded"); + t.ok(sharedTile.getAttribute("src") in layer.tileCache, "shared tile still in cache"); + firstInCache = layer.tileCache[layer.tileCacheIndex[0]]; + map.setCenter([16, 48]); + }); + t.delay_call(6, function() { + t.ok(!(firstInCache.getAttribute("src") in layer.tileCache), "old tile discarded"); + t.ok(sharedTile.getAttribute("src") in layer.tileCache, "shared tile still in cache"); + }); + } + function test_queueTileDraw(t) { t.plan(3); OpenLayers.Layer.Grid.prototype.queueTileDraw = origQueueTileDraw; From 80fa25164976e86c8229b283b96acfbdbbf9d76a Mon Sep 17 00:00:00 2001 From: ahocevar Date: Thu, 29 Nov 2012 14:52:53 -0600 Subject: [PATCH 030/123] New TileManager This removes all tile queueing/loading specific code from Layer.Grid and creates a new class that manages tile loading and caching. --- examples/mobile-base.js | 3 +- examples/mobile-wmts-vienna.js | 3 +- lib/OpenLayers.js | 1 + lib/OpenLayers/Layer/Bing.js | 19 +- lib/OpenLayers/Layer/Grid.js | 192 +--------- lib/OpenLayers/Tile.js | 16 +- lib/OpenLayers/Tile/Image.js | 33 +- lib/OpenLayers/TileManager.js | 334 ++++++++++++++++++ tests/Layer/ArcGIS93Rest.html | 3 - tests/Layer/Bing.html | 3 +- tests/Layer/Grid.html | 86 +---- tests/Layer/WMS.html | 4 - tests/Tile.html | 2 +- tests/TileManager.html | 107 ++++++ tests/deprecated/Layer/MapServer/Untiled.html | 3 - tests/list-tests.html | 1 + 16 files changed, 499 insertions(+), 311 deletions(-) create mode 100644 lib/OpenLayers/TileManager.js create mode 100644 tests/TileManager.html diff --git a/examples/mobile-base.js b/examples/mobile-base.js index 5440f932e2..d47ae3fd88 100644 --- a/examples/mobile-base.js +++ b/examples/mobile-base.js @@ -3,7 +3,7 @@ var apiKey = "AqTGBsziZHIJYYxgivLBf0hVdrAk9mWO5cQcb8Yux8sW5M8c8opEC2lZqKR1ZZXf"; // initialize map when page ready -var map; +var map, tileManager; var gg = new OpenLayers.Projection("EPSG:4326"); var sm = new OpenLayers.Projection("EPSG:900913"); @@ -85,6 +85,7 @@ var init = function (onSelectFeatureFunction) { center: new OpenLayers.LonLat(0, 0), zoom: 1 }); + tileManager = new OpenLayers.TileManager({map: map}); var style = { fillOpacity: 0.1, diff --git a/examples/mobile-wmts-vienna.js b/examples/mobile-wmts-vienna.js index 05a97e3a66..f7b8a8116d 100644 --- a/examples/mobile-wmts-vienna.js +++ b/examples/mobile-wmts-vienna.js @@ -1,4 +1,4 @@ -var map; +var map, tileManager; (function() { // Set document language for css content @@ -124,6 +124,7 @@ var map; } } }); + tileManager = new OpenLayers.TileManager({map: map}); layerPanel.activateControl(mapButton); layerPanel.activateControl(labelButton); diff --git a/lib/OpenLayers.js b/lib/OpenLayers.js index 4df00ddf62..f1344cbff9 100644 --- a/lib/OpenLayers.js +++ b/lib/OpenLayers.js @@ -395,6 +395,7 @@ "OpenLayers/Lang.js", "OpenLayers/Lang/en.js", "OpenLayers/Spherical.js", + "OpenLayers/TileManager.js", "OpenLayers/WPSClient.js", "OpenLayers/WPSProcess.js" ]; // etc. diff --git a/lib/OpenLayers/Layer/Bing.js b/lib/OpenLayers/Layer/Bing.js index 06af556cf2..06711b6a99 100644 --- a/lib/OpenLayers/Layer/Bing.js +++ b/lib/OpenLayers/Layer/Bing.js @@ -197,20 +197,12 @@ OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, { res.zoomMax + 1 - res.zoomMin, this.numZoomLevels ) }, true); + if (!this.isBaseLayer) { + this.redraw(); + } this.updateAttribution(); }, - - /** - * Method: drawTilesFromQueue - * Draws tiles from the tileQueue, and unqueues the tiles - */ - drawTilesFromQueue: function() { - // don't start working on the queue before we have a url from initLayer - if (this.url) { - OpenLayers.Layer.XYZ.prototype.drawTilesFromQueue.apply(this, arguments); - } - }, - + /** * Method: getURL * @@ -218,6 +210,9 @@ OpenLayers.Layer.Bing = OpenLayers.Class(OpenLayers.Layer.XYZ, { * bounds - {} */ getURL: function(bounds) { + if (!this.url) { + return; + } var xyz = this.getXYZ(bounds), x = xyz.x, y = xyz.y, z = xyz.z; var quadDigits = []; for (var i = z; i > 0; --i) { diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index 28ae7734d5..564789b6a3 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -113,14 +113,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { */ numLoadingTiles: 0, - /** - * APIProperty: tileLoadingDelay - * {Integer} Number of milliseconds before we shift and load - * tiles when panning. Ignored if is - * true. Default is 85. - */ - tileLoadingDelay: 85, - /** * Property: serverResolutions * {Array(Number}} This property is documented in subclasses as @@ -128,32 +120,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { */ serverResolutions: null, - /** - * Property: moveTimerId - * {Number} The id of the timer. - */ - moveTimerId: null, - - /** - * Property: deferMoveGriddedTiles - * {Function} A function that defers execution of by - * . If is true, this - * is null and unused. - */ - deferMoveGriddedTiles: null, - - /** - * Property: tileQueueId - * {Number} The id of the animation. - */ - tileQueueId: null, - - /** - * Property: tileQueue - * {Array()} Tiles queued for drawing. - */ - tileQueue: null, - /** * Property: loading * {Boolean} Indicates if tiles are being loaded. @@ -241,26 +207,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { */ className: null, - /** - * Property: tileCache - * {Object} Cached image elements, keyed by URL. - */ - tileCache: null, - - /** - * Property: tileCacheIndex - * {Array} URLs of cached tiles; first entry is least recently - * used. - */ - tileCacheIndex: null, - - /** - * APIProperty: tileCacheSize - * {Number} Number of image elements to keep referenced for fast reuse. - * Default is 128 per layer. - */ - tileCacheSize: 128, - /** * Register a listener for a particular event with the following syntax: * (code) @@ -275,6 +221,9 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { * element - {DOMElement} A reference to layer.events.element. * * Supported event types: + * addtile - Triggered when a tile is added to this layer. Listeners receive + * an object as first argument, which has a tile property that + * references the tile that has been added. * tileloadstart - Triggered when a tile starts loading. Listeners receive * an object as first argument, which has a tile property that * references the tile that starts loading. @@ -289,6 +238,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { * still hidden) if a tile failed to load. Listeners receive an object * as first argument, which has a tile property that references the * tile that could not be loaded. + * retile - Triggered when the layer recreates its tile grid. */ /** @@ -342,13 +292,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { 'olLayerGrid'; } - if (!OpenLayers.Animation.isNative) { - this.deferMoveGriddedTiles = OpenLayers.Function.bind(function() { - this.moveGriddedTiles(true); - this.moveTimerId = null; - }, this); - } - this.rowSign = this.tileOriginCorner.substr(0, 1) === "t" ? 1 : -1; }, @@ -375,7 +318,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { window.clearTimeout(this.moveTimerId); this.moveTimerId = null; } - this.clearTileQueue(); if(this.backBufferTimerId !== null) { window.clearTimeout(this.backBufferTimerId); this.backBufferTimerId = null; @@ -392,7 +334,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { this.grid = null; this.tileSize = null; - this.tileCache = null; OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments); }, @@ -402,7 +343,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { * destroy() on each of them to kill circular references */ clearGrid:function() { - this.clearTileQueue(); if (this.grid) { for(var iRow=0, len=this.grid.length; iRow= this.tileCacheSize) { - delete this.tileCache[this.tileCacheIndex[0]]; - this.tileCacheIndex.shift(); - } - this.tileCache[tile.url] = tile.imgDiv; - this.tileCacheIndex.push(tile.url); - } - }); - } - }, - - /** - * Method: clearTileQueue - * Clears the animation queue - */ - clearTileQueue: function() { - window.clearInterval(this.tileQueueId); - this.tileQueueId = null; - this.tileQueue = []; - }, - /** * Method: destroyTile * @@ -843,10 +695,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { this.div.removeChild(this.backBuffer); this.backBuffer = null; this.backBufferResolution = null; - if(this.backBufferTimerId !== null) { - window.clearTimeout(this.backBufferTimerId); - this.backBufferTimerId = null; - } } }, @@ -914,7 +762,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { * bounds - {} */ initSingleTile: function(bounds) { - this.clearTileQueue(); + this.events.triggerEvent("retile"); //determine new tile bounds var center = bounds.getCenterLonLat(); @@ -1047,7 +895,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { * bounds - {} */ initGriddedTiles:function(bounds) { - this.clearTileQueue(); + this.events.triggerEvent("retile"); // work out mininum number of rows and columns; this is the number of // tiles required to cover the viewport plus at least one for panning @@ -1126,8 +974,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { //shave off exceess rows and colums this.removeExcessTiles(rowidx, colidx); - var resolution = this.getServerResolution(), - immediately = resolution === this.gridResolution; + var resolution = this.getServerResolution(); // store the resolution of the grid this.gridResolution = resolution; @@ -1136,7 +983,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { return a.distance - b.distance; }); for (var i=0, ii=tileData.length; i and return the result from . * * Parameters: - * immediately - {Boolean} When e.g. drawing was aborted by returning false - * from a *beforedraw* listener, the queue manager needs to pass true, - * so the tile will not be cleared and immediately be drawn. Otherwise, - * the tile will be cleared and a *beforedraw* event will be fired. + * force - {Boolean} No beforedraw event will be fired. * * Returns: - * {Boolean} Whether or not the tile should actually be drawn. + * {Boolean} Whether or not the tile should actually be drawn. Retruns null + * if a beforedraw listener returned false. */ - draw: function(immediately) { - if (!immediately) { + draw: function(force) { + if (!force) { //clear tile's contents and mark as not drawn this.clear(); } var draw = this.shouldDraw(); - if (draw && !immediately) { - draw = this.events.triggerEvent("beforedraw") !== false; + if (draw && !force && this.events.triggerEvent("beforedraw") === false) { + draw = null; } return draw; }, diff --git a/lib/OpenLayers/Tile/Image.js b/lib/OpenLayers/Tile/Image.js index 76107d09e8..608e81a4ef 100644 --- a/lib/OpenLayers/Tile/Image.js +++ b/lib/OpenLayers/Tile/Image.js @@ -146,11 +146,12 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { * Check that a tile should be drawn, and draw it. * * Returns: - * {Boolean} Was a tile drawn? + * {Boolean} Was a tile drawn? Or null if a beforedraw listener returned + * false. */ draw: function() { - var drawn = OpenLayers.Tile.prototype.draw.apply(this, arguments); - if (drawn) { + var shouldDraw = OpenLayers.Tile.prototype.draw.apply(this, arguments); + if (shouldDraw) { // The layer's reproject option is deprecated. if (this.layer != this.layer.map.baseLayer && this.layer.reproject) { // getBoundsFromBaseLayer is defined in deprecated.js. @@ -158,17 +159,17 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { } if (this.isLoading) { //if we're already loading, send 'reload' instead of 'loadstart'. - this._loadEvent = "reload"; + this._loadEvent = "reload"; } else { this.isLoading = true; this._loadEvent = "loadstart"; } this.positionTile(); this.renderTile(); - } else { + } else if (shouldDraw === false) { this.unload(); } - return drawn; + return shouldDraw; }, /** @@ -287,9 +288,11 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { this.events.triggerEvent(this._loadEvent); var img = this.getImage(); if (this.url && img.getAttribute("src") == this.url) { - this.onImageLoad(); + this._loadTimeout = window.setTimeout( + OpenLayers.Function.bind(this.onImageLoad, this), 0 + ); } else { - OpenLayers.Event.stopObservingElement(img); + this.stopLoading(); if (this.crossOriginKeyword) { img.removeAttribute("crossorigin"); } @@ -328,7 +331,7 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { } else { // Remove reference to the image, and leave it to the browser's // caching and garbage collection. - OpenLayers.Event.stopObservingElement(this.imgDiv); + this.stopLoading(); this.imgDiv = null; if (img.parentNode) { img.parentNode.removeChild(img); @@ -378,7 +381,7 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { */ onImageLoad: function() { var img = this.imgDiv; - OpenLayers.Event.stopObservingElement(img); + this.stopLoading(); img.style.visibility = 'inherit'; img.style.opacity = this.layer.opacity; this.isLoading = false; @@ -409,6 +412,16 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { } } }, + + /** + * Method: stopLoading + * Stops a loading sequence so won't be executed. + */ + stopLoading: function() { + OpenLayers.Event.stopObservingElement(this.imgDiv); + window.clearTimeout(this._loadTimeout); + delete this._loadTimeout; + }, /** * APIMethod: getCanvasContext diff --git a/lib/OpenLayers/TileManager.js b/lib/OpenLayers/TileManager.js new file mode 100644 index 0000000000..db035c6e07 --- /dev/null +++ b/lib/OpenLayers/TileManager.js @@ -0,0 +1,334 @@ +/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for + * full list of contributors). Published under the 2-clause BSD license. + * See license.txt in the OpenLayers distribution or repository for the + * full text of the license. */ + + +/** + * @requires OpenLayers/Layer/Grid.js + * @requires OpenLayers/Util.js + * @requires OpenLayers/BaseTypes.js + * @requires OpenLayers/BaseTypes/Element.js + */ + +/** + * Class: OpenLayers.TileManager + * Provides queueing of image requests and caching of image elements. + * + * Queueing avoids unnecessary image requests while changing zoom levels + * quickly, and helps improve dragging performance on mobile devices that show + * a lag in dragging when loading of new images start. and + * are the configuration options to control this behavior. + * + * Caching avoids setting the src on image elements for images that have already + * been used. A TileManager instance can have a private cache (when configured + * with a ), or share a cache with other instances, in which case the + * cache size can be controlled by adjusting . + */ +OpenLayers.TileManager = OpenLayers.Class({ + + /** + * APIProperty: map + * {} The map to manage tiles on. + */ + map: null, + + /** + * APIProperty: cacheSize + * {Number} Number of image elements to keep referenced in this instance's + * private cache for fast reuse. If not set, this instance will use the + * shared cache. To configure the shared cache size, set + * . + */ + cacheSize: null, + + /** + * APIProperty: moveDelay + * {Number} Delay in milliseconds after a map's move event before loading + * tiles. Default is 100. + */ + moveDelay: 100, + + /** + * APIProperty: zoomDelay + * {Number} Delay in milliseconds after a map's zoomend event before loading + * tiles. Default is 200. + */ + zoomDelay: 200, + + /** + * Property: tileQueueId + * {Number} The id of the animation. + */ + tileQueueId: null, + + /** + * Property: tileQueue + * {Array()} Tiles queued for drawing. + */ + tileQueue: null, + + /** + * Property: tileCache + * {Object} Cached image elements, keyed by URL. This is shared among all + * TileManager instances, unless is set on the instance. + */ + tileCache: {}, + + /** + * Property: tileCacheIndex + * {Array} URLs of cached tiles; first entry is least recently + * used. This is shared among all TileManager instances, unless + * is set on the instance. + */ + tileCacheIndex: [], + + /** + * Constructor: OpenLayers.TileManager + * Constructor for a new instance. + * + * Parameters: + * options - {Object} Configuration for this instance. + * + * Required options: + * map - {} The map to manage tiles on. + */ + initialize: function(options) { + OpenLayers.Util.extend(this, options); + this.tileQueue = []; + if (this.cacheSize == null) { + this.cacheSize = OpenLayers.TileManager.cacheSize; + } else { + this.tileCache = {}; + this.tileCacheIndex = []; + } + var map = this.map; + for (var i=0, ii=map.layers.length; i=0; --i) { + for (j=layer.grid[i].length-1; j>=0; --j) { + tile = layer.grid[i][j]; + this.addTile({tile: tile}); + if (tile.url) { + this.manageTileCache({object: tile}); + } + } + } + } + }, + + /** + * Method: addLayer + * Handles the map's removelayer event + * + * Parameters: + * evt - {Object} The listener argument + */ + removeLayer: function(evt) { + var layer = evt.layer; + if (layer instanceof OpenLayers.Layer.Grid) { + this.clearTileQueue({object: layer}); + layer.events.un({ + addtile: this.addTile, + retile: this.clearTileQueue, + scope: this + }); + } + }, + + /** + * Method: updateTimeout + * Applies the or to the loop. + * + * Parameters: + * delay - {Number} The delay to apply + */ + updateTimeout: function(delay) { + window.clearTimeout(this.tileQueueId); + if (this.tileQueue.length) { + this.tileQueueId = window.setTimeout( + OpenLayers.Function.bind(this.drawTilesFromQueue, this), + delay + ); + } + }, + + /** + * Method: addTile + * Listener for the layer's addtile event + * + * Parameters: + * evt - {Object} The listener argument + */ + addTile: function(evt) { + evt.tile.events.on({ + beforedraw: this.queueTileDraw, + loadstart: this.manageTileCache, + reload: this.manageTileCache, + unload: this.unloadTile, + scope: this + }); + }, + + /** + * Method: unloadTile + * Listener for the tile's unload event + * + * Parameters: + * evt - {Object} The listener argument + */ + unloadTile: function(evt) { + evt.object.events.un({ + beforedraw: this.queueTileDraw, + loadstart: this.manageTileCache, + reload: this.manageTileCache, + loadend: this.addToCache, + unload: this.unloadTile, + scope: this + }); + OpenLayers.Util.removeItem(this.tileQueue, evt.object); + }, + + /** + * Method: queueTileDraw + * Adds a tile to the queue that will draw it. + * + * Parameters: + * evt - {Object} Listener argument of the tile's beforedraw event + */ + queueTileDraw: function(evt) { + var tile = evt.object; + var queued = false; + var layer = tile.layer; + // queue only if image with same url not cached already + if (layer.url && (layer.async || + !this.tileCache[layer.getURL(tile.bounds)])) { + // add to queue only if not in queue already + if (!~OpenLayers.Util.indexOf(this.tileQueue, tile)) { + this.tileQueue.push(tile); + } + queued = true; + } + return !queued; + }, + + /** + * Method: drawTilesFromQueue + * Draws tiles from the tileQueue, and unqueues the tiles + */ + drawTilesFromQueue: function() { + while (this.tileQueue.length) { + this.tileQueue.shift().draw(true); + } + }, + + /** + * Method: manageTileCache + * Adds, updates, removes and fetches cache entries. + * + * Parameters: + * evt - {Object} Listener argument of the tile's loadstart event + */ + manageTileCache: function(evt) { + var tile = evt.object; + var img = this.tileCache[tile.url]; + // only use images from the cache that are not on a layer already + if (img && (!img.parentNode || + OpenLayers.Element.hasClass(img.parentNode, 'olBackBuffer'))) { + tile.imgDiv = img; + OpenLayers.Util.removeItem(this.tileCacheIndex, tile.url); + this.tileCacheIndex.push(tile.url); + tile.positionTile(); + tile.layer.div.appendChild(tile.imgDiv); + } else if (evt.type === 'loadstart') { + tile.events.register('loadend', this, this.addToCache); + } + }, + + /** + * Method: addToCache + * + * Parameters: + * evt - {Object} Listener argument for the tile's loadend event + */ + addToCache: function(evt) { + var tile = evt.object; + tile.events.unregister('loadend', this, this.addToCache); + if (!this.tileCache[tile.url]) { + if (!OpenLayers.Element.hasClass(tile.imgDiv, 'olImageLoadError')) { + if (this.tileCacheIndex.length >= this.cacheSize) { + delete this.tileCache[this.tileCacheIndex[0]]; + this.tileCacheIndex.shift(); + } + this.tileCache[tile.url] = tile.imgDiv; + this.tileCacheIndex.push(tile.url); + } + } + }, + + /** + * Method: clearTileQueue + * Clears the tile queue from tiles of a specific layer + * + * Parameters: + * evt - {Object} Listener argument of the layer's retile event + */ + clearTileQueue: function(evt) { + var layer = evt.object; + for (var i=this.tileQueue.length-1; i>=0; --i) { + if (this.tileQueue[i].layer === layer) { + this.tileQueue.splice(i, 1); + } + } + } + +}); + +/** + * APIProperty: OpenLayers.TileManager.cacheSize + * {Number} Number of image elements to keep referenced in the shared cache + * for fast reuse. Default is 512. + */ +OpenLayers.TileManager.cacheSize = 512; \ No newline at end of file diff --git a/tests/Layer/ArcGIS93Rest.html b/tests/Layer/ArcGIS93Rest.html index 6c00732e4e..568dff0326 100644 --- a/tests/Layer/ArcGIS93Rest.html +++ b/tests/Layer/ArcGIS93Rest.html @@ -4,9 +4,6 @@ + + + + + + \ No newline at end of file diff --git a/tests/deprecated/Layer/MapServer/Untiled.html b/tests/deprecated/Layer/MapServer/Untiled.html index c3f9c44fe4..1b1dc94f36 100644 --- a/tests/deprecated/Layer/MapServer/Untiled.html +++ b/tests/deprecated/Layer/MapServer/Untiled.html @@ -5,9 +5,6 @@ From 273657a6ab4d25f4f0855354e9d416eff80c9978 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Fri, 30 Nov 2012 10:26:19 -0600 Subject: [PATCH 033/123] Adding API docs for the tileManager property --- lib/OpenLayers/Map.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/OpenLayers/Map.js b/lib/OpenLayers/Map.js index 8077d73c70..3e29852a9f 100644 --- a/lib/OpenLayers/Map.js +++ b/lib/OpenLayers/Map.js @@ -370,6 +370,14 @@ OpenLayers.Map = OpenLayers.Class({ * property at the time the control is added to the map. */ displayProjection: null, + + /** + * APIProperty: tileManager + * {} If configured at construction time, the map + * will use the TileManager to queue image requests and to cache tile image + * elements. + */ + tileManager: null, /** * APIProperty: fallThrough From ecbedf5536e17aa9b91a085ca48f215ac02c4af0 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Fri, 14 Dec 2012 09:19:06 +0100 Subject: [PATCH 034/123] Updating tests --- tests/Layer/Bing.html | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/tests/Layer/Bing.html b/tests/Layer/Bing.html index e43bfc82d3..89bbba7584 100644 --- a/tests/Layer/Bing.html +++ b/tests/Layer/Bing.html @@ -1,19 +1,5 @@ - + + + + + diff --git a/tests/list-tests.html b/tests/list-tests.html index 8c37464b84..dfcaa2f4a0 100644 --- a/tests/list-tests.html +++ b/tests/list-tests.html @@ -66,6 +66,7 @@
  • Format/XML/VersionedOGC.html
  • Format/ArcXML/Features.html
  • Format/CQL.html
  • +
  • Format/EncodedPolyline.html
  • Format/GeoJSON.html
  • Format/GeoRSS.html
  • Format/GML.html
  • From b6c2c26580fcbc2bf2f5884a61ba9b44cf62e9df Mon Sep 17 00:00:00 2001 From: Christopher Eykamp Date: Thu, 27 Dec 2012 13:29:02 +0100 Subject: [PATCH 043/123] WCS parsing working properly, but needs more tests; moved errorProperty down to parser, where it arguably belongs, and where it has to live to work with WCS. Also removed null error property on versionedOGC. --- lib/OpenLayers/Format/WCSCapabilities.js | 8 -------- .../Format/WCSCapabilities/v1_0_0.js | 10 ++++++++++ .../Format/WCSCapabilities/v1_1_0.js | 9 +++++++++ lib/OpenLayers/Format/WFSCapabilities.js | 9 --------- lib/OpenLayers/Format/WFSCapabilities/v1.js | 10 ++++++++++ lib/OpenLayers/Format/XML/VersionedOGC.js | 18 +++++++----------- tests/Format/WCSCapabilities/v1.html | 3 --- 7 files changed, 36 insertions(+), 31 deletions(-) diff --git a/lib/OpenLayers/Format/WCSCapabilities.js b/lib/OpenLayers/Format/WCSCapabilities.js index ae034a5227..082805602c 100644 --- a/lib/OpenLayers/Format/WCSCapabilities.js +++ b/lib/OpenLayers/Format/WCSCapabilities.js @@ -22,14 +22,6 @@ OpenLayers.Format.WCSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.Versi */ defaultVersion: "1.1.0", - /** - * APIProperty: errorProperty - * {String} Which property of the returned object to check for in order to - * determine whether or not parsing has failed. In the case that the - * errorProperty is undefined on the returned object, the document will be - * run through an OGCExceptionReport parser. - */ - errorProperty: "service", /** * Constructor: OpenLayers.Format.WCSCapabilities diff --git a/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js b/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js index e68b004a74..ca0799ac79 100644 --- a/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js +++ b/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js @@ -38,6 +38,16 @@ OpenLayers.Format.WCSCapabilities.v1_0_0 = OpenLayers.Class( ows: "http://www.opengis.net/ows" }, + /** + * APIProperty: errorProperty + * {String} Which property of the returned object to check for in order to + * determine whether or not parsing has failed. In the case that the + * errorProperty is undefined on the returned object, the document will be + * run through an OGCExceptionReport parser. + */ + errorProperty: "service", + + /** * Property: readers * Contains public functions, grouped by namespace prefix, that will diff --git a/lib/OpenLayers/Format/WCSCapabilities/v1_1_0.js b/lib/OpenLayers/Format/WCSCapabilities/v1_1_0.js index b991bca48e..7e2061afcb 100644 --- a/lib/OpenLayers/Format/WCSCapabilities/v1_1_0.js +++ b/lib/OpenLayers/Format/WCSCapabilities/v1_1_0.js @@ -30,6 +30,15 @@ OpenLayers.Format.WCSCapabilities.v1_1_0 = OpenLayers.Class( ows: "http://www.opengis.net/ows/1.1" }, + /** + * APIProperty: errorProperty + * {String} Which property of the returned object to check for in order to + * determine whether or not parsing has failed. In the case that the + * errorProperty is undefined on the returned object, the document will be + * run through an OGCExceptionReport parser. + */ + errorProperty: "operationsMetadata", + /** * Constructor: OpenLayers.Format.WCSCapabilities.v1_1_0 diff --git a/lib/OpenLayers/Format/WFSCapabilities.js b/lib/OpenLayers/Format/WFSCapabilities.js index ec82ae984b..ba4598645b 100644 --- a/lib/OpenLayers/Format/WFSCapabilities.js +++ b/lib/OpenLayers/Format/WFSCapabilities.js @@ -21,15 +21,6 @@ OpenLayers.Format.WFSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.Versi * {String} Version number to assume if none found. Default is "1.1.0". */ defaultVersion: "1.1.0", - - /** - * APIProperty: errorProperty - * {String} Which property of the returned object to check for in order to - * determine whether or not parsing has failed. In the case that the - * errorProperty is undefined on the returned object, the document will be - * run through an OGCExceptionReport parser. - */ - errorProperty: "featureTypeList", /** * Constructor: OpenLayers.Format.WFSCapabilities diff --git a/lib/OpenLayers/Format/WFSCapabilities/v1.js b/lib/OpenLayers/Format/WFSCapabilities/v1.js index bd52c61cea..65a5faa8a0 100644 --- a/lib/OpenLayers/Format/WFSCapabilities/v1.js +++ b/lib/OpenLayers/Format/WFSCapabilities/v1.js @@ -28,6 +28,16 @@ OpenLayers.Format.WFSCapabilities.v1 = OpenLayers.Class( ows: "http://www.opengis.net/ows" }, + + /** + * APIProperty: errorProperty + * {String} Which property of the returned object to check for in order to + * determine whether or not parsing has failed. In the case that the + * errorProperty is undefined on the returned object, the document will be + * run through an OGCExceptionReport parser. + */ + errorProperty: "featureTypeList", + /** * Property: defaultPrefix */ diff --git a/lib/OpenLayers/Format/XML/VersionedOGC.js b/lib/OpenLayers/Format/XML/VersionedOGC.js index 4aceee6988..c2cb97471b 100644 --- a/lib/OpenLayers/Format/XML/VersionedOGC.js +++ b/lib/OpenLayers/Format/XML/VersionedOGC.js @@ -45,14 +45,6 @@ OpenLayers.Format.XML.VersionedOGC = OpenLayers.Class(OpenLayers.Format.XML, { */ allowFallback: false, - /** - * APIProperty: errorProperty - * {String} Which property of the returned object to check for in order to - * determine whether or not parsing has failed. In the case that the - * errorProperty is undefined on the returned object, the document will be - * run through an OGCExceptionReport parser. - */ - errorProperty: null, /** * Property: name @@ -193,9 +185,13 @@ OpenLayers.Format.XML.VersionedOGC = OpenLayers.Class(OpenLayers.Format.XML, { } var root = data.documentElement; var version = this.getVersion(root); - this.parser = this.getParser(version); - var obj = this.parser.read(data, options); - if (this.errorProperty !== null && obj[this.errorProperty] === undefined) { + this.parser = this.getParser(version); // Select the parser + var obj = this.parser.read(data, options); // Parse the data + + var errorProperty = this.parser.errorProperty || null; + + + if (errorProperty !== null && obj[errorProperty] === undefined) { // an error must have happened, so parse it and report back var format = new OpenLayers.Format.OGCExceptionReport(); obj.error = format.read(data); diff --git a/tests/Format/WCSCapabilities/v1.html b/tests/Format/WCSCapabilities/v1.html index ac4096b335..646ca47f3e 100644 --- a/tests/Format/WCSCapabilities/v1.html +++ b/tests/Format/WCSCapabilities/v1.html @@ -30,7 +30,6 @@ var res = parser.read(text); - debugger; t.ok(!res.error, "Parsing XML generated no errors"); t.eq(res.service.fees, "mucho dinero", "Service>Fees correctly parsed"); @@ -64,8 +63,6 @@ res = parser.read(text); -debugger; - t.ok(!res.error, "Parsing XML generated no errors"); // ft = res.featureTypeList.featureTypes; From 809ecb1155716c5bb1afd17b0e622ac566b0b470 Mon Sep 17 00:00:00 2001 From: Christopher Eykamp Date: Thu, 27 Dec 2012 13:47:16 +0100 Subject: [PATCH 044/123] Remove uneeded readers from WCS 1.0.0 --- .../Format/WCSCapabilities/v1_0_0.js | 25 +------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js b/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js index ca0799ac79..2fdd6d19df 100644 --- a/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js +++ b/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js @@ -46,7 +46,7 @@ OpenLayers.Format.WCSCapabilities.v1_0_0 = OpenLayers.Class( * run through an OGCExceptionReport parser. */ errorProperty: "service", - + /** * Property: readers @@ -188,30 +188,7 @@ OpenLayers.Format.WCSCapabilities.v1_0_0 = OpenLayers.Class( coverageOfferingBrief.lonLatEnvelope.max = max; } } - }, - - //////////////////////////////////////////////////////////////////////////////////////////// - - - "DCPType": function(node, obj) { - this.readChildNodes(node, obj); - }, - "HTTP": function(node, obj) { - this.readChildNodes(node, obj.href); - }, - "Get": function(node, obj) { - obj.get = node.getAttribute("onlineResource"); - }, - "Post": function(node, obj) { - obj.post = node.getAttribute("onlineResource"); - }, - "SRS": function(node, obj) { - var srs = this.getChildValue(node); - if (srs) { - obj.srs = srs; - } - } }, OpenLayers.Format.WCSCapabilities.v1.prototype.readers["wcs"]) }, From 5a19c74604fcebca64b39f286d625a79e6d2fcad Mon Sep 17 00:00:00 2001 From: Christopher Eykamp Date: Thu, 27 Dec 2012 13:47:37 +0100 Subject: [PATCH 045/123] Whitespace --- lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js b/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js index 2fdd6d19df..f1f63f1de3 100644 --- a/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js +++ b/lib/OpenLayers/Format/WCSCapabilities/v1_0_0.js @@ -38,6 +38,7 @@ OpenLayers.Format.WCSCapabilities.v1_0_0 = OpenLayers.Class( ows: "http://www.opengis.net/ows" }, + /** * APIProperty: errorProperty * {String} Which property of the returned object to check for in order to From a8f1c7681107a5a7ef36096bd53e7d31f6eeb518 Mon Sep 17 00:00:00 2001 From: Christopher Eykamp Date: Thu, 27 Dec 2012 13:48:38 +0100 Subject: [PATCH 046/123] Whitespace --- lib/OpenLayers/Format/XML/VersionedOGC.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/OpenLayers/Format/XML/VersionedOGC.js b/lib/OpenLayers/Format/XML/VersionedOGC.js index c2cb97471b..3561085e90 100644 --- a/lib/OpenLayers/Format/XML/VersionedOGC.js +++ b/lib/OpenLayers/Format/XML/VersionedOGC.js @@ -189,8 +189,6 @@ OpenLayers.Format.XML.VersionedOGC = OpenLayers.Class(OpenLayers.Format.XML, { var obj = this.parser.read(data, options); // Parse the data var errorProperty = this.parser.errorProperty || null; - - if (errorProperty !== null && obj[errorProperty] === undefined) { // an error must have happened, so parse it and report back var format = new OpenLayers.Format.OGCExceptionReport(); From be7c55f4325d9fd1da9cdc51344c55cfc6186352 Mon Sep 17 00:00:00 2001 From: Christopher Eykamp Date: Thu, 27 Dec 2012 14:28:46 +0100 Subject: [PATCH 047/123] Added full suite of wcs 1.1.0 tests, all are passing --- .../Format/WCSCapabilities/v1_1_0.js | 11 +- tests/Format/WCSCapabilities/v1.html | 195 ++++-------------- 2 files changed, 46 insertions(+), 160 deletions(-) diff --git a/lib/OpenLayers/Format/WCSCapabilities/v1_1_0.js b/lib/OpenLayers/Format/WCSCapabilities/v1_1_0.js index 7e2061afcb..cdd1db21f9 100644 --- a/lib/OpenLayers/Format/WCSCapabilities/v1_1_0.js +++ b/lib/OpenLayers/Format/WCSCapabilities/v1_1_0.js @@ -65,15 +65,14 @@ OpenLayers.Format.WCSCapabilities.v1_1_0 = OpenLayers.Class( }, "Contents": function(node, request) { - var contents = []; - this.readChildNodes(node, contents); - - request.contents = contents; + request.contents = []; + this.readChildNodes(node, request.contents); }, "CoverageSummary": function(node, contents) { - contents.coverageSummary = {}; - this.readChildNodes(node, contents.coverageSummary); + var coverageSummary = {}; + this.readChildNodes(node, coverageSummary); // Read the summary + contents.push(coverageSummary); // Add it to the contents array }, "Identifier": function(node, coverageSummary) { diff --git a/tests/Format/WCSCapabilities/v1.html b/tests/Format/WCSCapabilities/v1.html index 646ca47f3e..7579cdb98c 100644 --- a/tests/Format/WCSCapabilities/v1.html +++ b/tests/Format/WCSCapabilities/v1.html @@ -7,21 +7,21 @@ t.plan(1); var parser = new OpenLayers.Format.WCSCapabilities(); var text = '' + -'' + -' ' + -' Update error: Error occured updating features' + -' Second exception line' + -' ' + -''; + '' + + ' ' + + ' Update error: Error occured updating features' + + ' Second exception line' + + ' ' + + ''; var obj = parser.read(text); t.ok(!!obj.error, "Error reported correctly"); // The above should place an error in obj.error } function test_read(t) { - t.plan(26); // Number of tests performed: If you add a test below, be sure to increment this accordingly + t.plan(34); // Number of tests performed: If you add a test below, be sure to increment this accordingly var parser = new OpenLayers.Format.WCSCapabilities(); @@ -30,7 +30,6 @@ var res = parser.read(text); - t.ok(!res.error, "Parsing XML generated no errors"); t.eq(res.service.fees, "mucho dinero", "Service>Fees correctly parsed"); t.eq(res.service.accessConstraints, "Open to the public", "Service>AccessConstraints correctly parsed"); @@ -38,162 +37,50 @@ t.eq(res.service.keywords[0], "Geospatial WebServices", "Service>Keywords correctly parsed"); t.eq(res.service.label, "WCS Sample Data Server 1.0.0", "Service>Label correctly parsed"); t.eq(res.service.name, "MapServer WCS", "Service>Name correctly parsed"); - t.eq(res.service.responsibleParty.individualName, "Franko Lemmer", "Service>ResponsibleParty>IndividualName correctly parsed"); - t.eq(res.service.responsibleParty.organisationName, "CRP Henri Tudor", "Service>ResponsibleParty>OrganisationName correctly parsed"); - t.eq(res.service.responsibleParty.positionName, "R+D engineer", "Service>ResponsibleParty>PositionName correctly parsed"); - t.eq(res.service.responsibleParty.contactInfo.address.city, "Esch-sur-Alzette", "Service>responsibleParty>ContactInfo>Address>City correctly parsed"); - t.eq(res.service.responsibleParty.contactInfo.address.country, "Luxembourg", "Service>responsibleParty>ContactInfo>Address>Country correctly parsed"); - t.eq(res.service.responsibleParty.contactInfo.address.deliveryPoint, "66, rue de Luxembourg", "Service>responsibleParty>ContactInfo>Address>DeliveryPoint correctly parsed"); - t.eq(res.service.responsibleParty.contactInfo.address.electronicMailAddress, "franko.lemmer@flensburger.de", "Service>responsibleParty>ContactInfo>Address>ElectronicMailAddress correctly parsed"); - t.eq(res.service.responsibleParty.contactInfo.address.postalCode, "97202", "Service>responsibleParty>ContactInfo>Address>PostalCode correctly parsed"); - t.eq(res.service.responsibleParty.contactInfo.phone.facsimile, "6465955", "Service>responsibleParty>ContactInfo>Phone>Facsimile correctly parsed"); - t.eq(res.service.responsibleParty.contactInfo.phone.voice, "6463320", "Service>responsibleParty>ContactInfo>Phone>Voice correctly parsed"); + + var responsibleParty = res.service.responsibleParty; + t.eq(responsibleParty.individualName, "Franko Lemmer", "Service>ResponsibleParty>IndividualName correctly parsed"); + t.eq(responsibleParty.organisationName, "CRP Henri Tudor", "Service>ResponsibleParty>OrganisationName correctly parsed"); + t.eq(responsibleParty.positionName, "R+D engineer", "Service>ResponsibleParty>PositionName correctly parsed"); + t.eq(responsibleParty.contactInfo.address.city, "Esch-sur-Alzette", "Service>responsibleParty>ContactInfo>Address>City correctly parsed"); + t.eq(responsibleParty.contactInfo.address.country, "Luxembourg", "Service>responsibleParty>ContactInfo>Address>Country correctly parsed"); + t.eq(responsibleParty.contactInfo.address.deliveryPoint, "66, rue de Luxembourg", "Service>responsibleParty>ContactInfo>Address>DeliveryPoint correctly parsed"); + t.eq(responsibleParty.contactInfo.address.electronicMailAddress, "franko.lemmer@flensburger.de", "Service>responsibleParty>ContactInfo>Address>ElectronicMailAddress correctly parsed"); + t.eq(responsibleParty.contactInfo.address.postalCode, "97202", "Service>responsibleParty>ContactInfo>Address>PostalCode correctly parsed"); + t.eq(responsibleParty.contactInfo.phone.facsimile, "6465955", "Service>responsibleParty>ContactInfo>Phone>Facsimile correctly parsed"); + t.eq(responsibleParty.contactInfo.phone.voice, "6463320", "Service>responsibleParty>ContactInfo>Phone>Voice correctly parsed"); + + var metadata = res.contentMetadata[0]; + t.eq(metadata.name, "ro_dsm", "ContentMetadata>Name correctly parsed"); + t.eq(metadata.label, "Rotterdam DSM", "ContentMetadata>Label correctly parsed"); + t.eq(metadata.lonLatEnvelope.min.lat, "51.515151", "ContentMetadata>lonLatEnvelope>Min>Lat correctly parsed"); + t.eq(metadata.lonLatEnvelope.min.lon, "4.44444", "ContentMetadata>lonLatEnvelope>Min>Lon correctly parsed"); + t.eq(metadata.lonLatEnvelope.max.lat, "52.525252", "ContentMetadata>lonLatEnvelope>Max>Lat correctly parsed"); + t.eq(metadata.lonLatEnvelope.max.lon, "5.55555", "ContentMetadata>lonLatEnvelope>Max>Lon correctly parsed"); + t.eq(metadata.lonLatEnvelope.srsName, "urn:ogc:def:crs:OGC:1.3:CRS84", "ContentMetadata>lonLatEnvelope>SrsName correctly parsed"); t.eq(res.contentMetadata.length, 4, "Correct number of metadata records found"); - t.eq(res.contentMetadata[0].label, "Rotterdam DSM", "ContentMetadata>Label correctly parsed"); - t.eq(res.contentMetadata[0].lonLatEnvelope.min.lat, "51.515151", "ContentMetadata>lonLatEnvelope>Min>Lat correctly parsed"); - t.eq(res.contentMetadata[0].lonLatEnvelope.min.lon, "4.44444", "ContentMetadata>lonLatEnvelope>Min>Lon correctly parsed"); - t.eq(res.contentMetadata[0].lonLatEnvelope.max.lat, "52.525252", "ContentMetadata>lonLatEnvelope>Max>Lat correctly parsed"); - t.eq(res.contentMetadata[0].lonLatEnvelope.max.lon, "5.55555", "ContentMetadata>lonLatEnvelope>Max>Lon correctly parsed"); - t.eq(res.contentMetadata[0].lonLatEnvelope.srsName, "urn:ogc:def:crs:OGC:1.3:CRS84", "ContentMetadata>lonLatEnvelope>SrsName correctly parsed"); - t.eq(res.contentMetadata[0].name, "ro_dsm", "ContentMetadata>Name correctly parsed"); // GeoServer, v1.1.0 text = 'Web-Service Demo with data stored at TUDOR siteThis installation serves different Web-Service types (WMS, WFS) for testingGeospatial WebServicesKeyword OneKeyword Two!!OGC WCS1.1.0No fee!Unconstrained!CRP Henri TudorRoy DumerdeR+D engineer6463320646595566, rue de LuxembourgEsch-sur-Alzette97202Luxembourgflappy@tutones.com24/7by phoneGIS-AnalystWCS1.1.0WCS1.1.0ro_dsmro_dsm_miniro_irraro_irra_extWCS1.1.0ro_dsmro_dsm_miniro_irraro_irra_extNEAREST_NEIGHBOURBILINEARimage/tiffimage/pngimage/jpegimage/gifimage/png; mode=8bitfalseurn:ogc:def:crs:epsg::4326Rotterdam DSMDigital Surface Model (DSM) raster data set of inner city Rotterdam4.471333734139 51.9128134273834.4808508475645 51.9248713705576urn:ogc:def:crs:EPSG::28992urn:ogc:def:crs:EPSG::900913urn:ogc:def:crs:EPSG::3857urn:ogc:def:crs:EPSG::4326image/tiffro_dsmRotterdam sample DSM subsetThis a test data set of Rotterdams DSM subset4.47489346945755 51.91594537869274.47687824892444 51.9170706688033urn:ogc:def:crs:EPSG::28992urn:ogc:def:crs:EPSG::900913urn:ogc:def:crs:EPSG::3857urn:ogc:def:crs:EPSG::4326image/tiffro_dsm_miniRotterdam (Ljinbaan) solar irradiation data 2010This a result data set of a solar computation of Ljinbaan area. It shows the sum of kWh/a per sqmeter for 20104.471333734139 51.9128134273834.4808508475645 51.9248713705576urn:ogc:def:crs:EPSG::28992urn:ogc:def:crs:EPSG::900913urn:ogc:def:crs:EPSG::3857urn:ogc:def:crs:EPSG::4326image/tiffro_irraRotterdam (extended) solar irradiation data 2010This a result data set of a solar computation of extended Rotterdam area. It shows the sum of kWh/a per sqmeter for 20104.10024171314823 51.93597649928444.21909054278063 52.001415228243urn:ogc:def:crs:EPSG::28992urn:ogc:def:crs:EPSG::900913urn:ogc:def:crs:EPSG::3857urn:ogc:def:crs:EPSG::4326image/tiffro_irra_ext'; - res = parser.read(text); + // Most of the parsing is handled by other objects, so not much actually requires testing here t.ok(!res.error, "Parsing XML generated no errors"); - // ft = res.featureTypeList.featureTypes; - // t.eq(ft.length, 14, "number of feature types correct"); - // t.eq(ft[0]["abstract"], "Manhattan landmarks, identifies water, lakes, parks, interesting buildilngs", "abstract of first feature type correct"); - // t.eq(ft[0]["title"], "Manhattan (NY) landmarks", "title of first feature type correct"); - // t.eq(ft[0]["name"], "poly_landmarks", "name of first feature type correct"); - // t.eq(ft[0]["featureNS"], "http://www.census.gov", "ns of first feature type correct"); - // t.eq(ft[0]["srs"], "EPSG:4326", "srs of first feature type correct"); + t.eq(res.contents.length, 4, "number of features correct"); - // var service = res.service; - // t.eq(service.name, 'WFS', "service name correct"); - // t.eq(service.title, 'GeoServer Web Feature Service', "service title correct"); - // t.eq(service.abstract, 'This is the reference implementation of WFS 1.0.0 and WFS 1.1.0, supports all WFS operations including Transaction.', "service title correct"); - // t.eq(service.keywords[0], 'WFS', "service keyword [0] correct"); - // t.eq(service.keywords[2], 'GEOSERVER', "service keyword [2] correct"); - // t.eq(service.onlineResource, 'http://localhost:80/geoserver/wfs', "service onlineresource correct"); - // t.ok(typeof service.fees == 'undefined', "service fees correct"); - // t.ok(typeof service.accessConstraints == 'undefined', "service accessconstraints correct"); - - // t.eq(res.capability.request.getfeature.href.post, "http://localhost:80/geoserver/wfs?", "getfeature request post href correct"); - // t.eq(res.capability.request.getfeature.href.get, "http://localhost:80/geoserver/wfs?request=GetFeature", "getfeature request get href correct"); - - // t.eq(res.capability.request.getfeature.formats[0], "GML2", "getfeature response format [0] correct"); - // t.eq(res.capability.request.getfeature.formats[4], "GML3", "getfeature response format [4] correct"); - - // // UMN Mapserer, v1.0.0 - // text = - // '' + - // '' + - // '' + - // '' + - // '' + - // '' + - // ' MapServer WFS' + - // ' GMap WMS Demo Server' + - // ' http://127.0.0.1/cgi-bin/mapserv_40?map=/msroot/apache/htdocs/gmap/htdocs/gmap75_wfs.map&service=WFS&' + - // '' + - // '' + - // '' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // '' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // '' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // '' + - // ' ' + - // ' ' + - // ' ' + - // '' + - // '' + - // '' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // '' + - // ' park' + - // ' Parks' + - // ' EPSG:42304' + - // ' ' + - // ' ' + - // ' ' + - // ' popplace' + - // '' + - // ' Cities' + - // ' EPSG:42304' + - // ' ' + - // ' ' + - // '' + - // '' + - // '' + - // ' ' + - // ' ' + - // '' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // ' ' + - // '' + - // '' + - // ''; - // res = parser.read(text); - // var ft = res.featureTypeList.featureTypes; - // t.eq(ft.length, 2, "number of feature types correct"); - // t.eq(ft[0]["title"], "Parks", "title of first feature type correct"); - // t.eq(ft[0]["name"], "park", "name of first feature type correct"); - // t.eq(ft[0]["srs"], "EPSG:42304", "srs of first feature type correct"); - - // var service = res.service; - // t.eq(service.name, 'MapServer WFS', "service name correct"); - // t.eq(service.title, 'GMap WMS Demo Server', "service title correct"); - // t.eq(service.onlineResource, 'http://127.0.0.1/cgi-bin/mapserv_40?map=/msroot/apache/htdocs/gmap/htdocs/gmap75_wfs.map&service=WFS&', "service onlineresource correct"); - // t.eq(res.capability.request.getfeature.href.get, "http://127.0.0.1/cgi-bin/mapserv_40?map=/msroot/apache/htdocs/gmap/htdocs/gmap75_wfs.map&service=WFS&", "getfeature request get href correct"); - // t.eq(res.capability.request.getfeature.formats[0], "GML2", "getfeature response format [0] correct"); + var contents = res.contents[0]; + t.eq(contents.identifier, "ro_dsm", "correct identifier"); + t.eq(contents.title, "Rotterdam DSM", "correct title"); + t.eq(contents.abstract, "Digital Surface Model (DSM) raster data set of inner city Rotterdam", "correct abstract"); + t.eq(contents.supportedFormat.length, 1, "correct number of supported formats"); + t.eq(contents.supportedFormat[0], "image/tiff", "correct format"); + t.eq(contents.supportedCRS.length, 4, "correct number of CRS records"); + t.eq(contents.supportedCRS[2], "urn:ogc:def:crs:EPSG::3857", "correct CRS"); } - - + From 0e9691c628bf439cbb9b1fa84ba72a4dac5a2bef Mon Sep 17 00:00:00 2001 From: Christopher Eykamp Date: Thu, 27 Dec 2012 14:40:28 +0100 Subject: [PATCH 048/123] Remove unused readers --- lib/OpenLayers/Format/WCSCapabilities/v1.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/lib/OpenLayers/Format/WCSCapabilities/v1.js b/lib/OpenLayers/Format/WCSCapabilities/v1.js index 89981f3f9d..c0d8d92b3c 100644 --- a/lib/OpenLayers/Format/WCSCapabilities/v1.js +++ b/lib/OpenLayers/Format/WCSCapabilities/v1.js @@ -71,18 +71,6 @@ OpenLayers.Format.WCSCapabilities.v1 = OpenLayers.Class( "wcs": { "WCS_Capabilities": function(node, obj) { // In 1.0.0, this was WCS_Capabilties, changed in 1.1.0 this.readChildNodes(node, obj); - }, - "Title": function(node, obj) { - var title = this.getChildValue(node); - if(title) { - obj.title = title; - } - }, - "Abstract": function(node, obj) { - var abst = this.getChildValue(node); - if(abst) { - obj["abstract"] = abst; - } } } }, From 16981a8afaf9478f0d30ffa00a0d927f9d2386f6 Mon Sep 17 00:00:00 2001 From: Christopher Eykamp Date: Thu, 27 Dec 2012 15:38:01 +0100 Subject: [PATCH 049/123] Remove unneeded files --- lib/OpenLayers/Protocol/WCS.js | 86 ----- lib/OpenLayers/Protocol/WCS/v1.js | 434 -------------------------- lib/OpenLayers/Protocol/WCS/v1_0_0.js | 43 --- lib/OpenLayers/Protocol/WCS/v1_1_0.js | 37 --- 4 files changed, 600 deletions(-) delete mode 100644 lib/OpenLayers/Protocol/WCS.js delete mode 100644 lib/OpenLayers/Protocol/WCS/v1.js delete mode 100644 lib/OpenLayers/Protocol/WCS/v1_0_0.js delete mode 100644 lib/OpenLayers/Protocol/WCS/v1_1_0.js diff --git a/lib/OpenLayers/Protocol/WCS.js b/lib/OpenLayers/Protocol/WCS.js deleted file mode 100644 index 9520e3fbc0..0000000000 --- a/lib/OpenLayers/Protocol/WCS.js +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Protocol.js - */ - -/** - * Class: OpenLayers.Protocol.WCS - * Used to create a versioned WCS protocol. Default version is 1.0.0. - * - * Returns: - * {} A WCS protocol of the given version. - * - * Example: - * (code) - * var protocol = new OpenLayers.Protocol.WCS({ - * version: "1.1.0", - * url: "http://demo.opengeo.org/geoserver/wcs", - * featureType: "tasmania_roads", - * featureNS: "http://www.openplans.org/topp", - * geometryName: "the_geom" - * }); - * (end) - * - * See the protocols for specific WCS versions for more detail. - */ -OpenLayers.Protocol.WCS = function(options) { - options = OpenLayers.Util.applyDefaults( - options, OpenLayers.Protocol.WCS.DEFAULTS - ); - var cls = OpenLayers.Protocol.WCS["v"+options.version.replace(/\./g, "_")]; - if(!cls) { - throw "Unsupported WCS version: " + options.version; - } - return new cls(options); -}; - -/** - * Function: fromWMSLayer - * Convenience function to create a WCS protocol from a WMS layer. This makes - * the assumption that a WCS requests can be issued at the same URL as - * WMS requests and that a WCS featureType exists with the same name as the - * WMS layer. - * - * This function is designed to auto-configure , , - * and for WCS 1.1.0. Note that - * srsName matching with the WMS layer will not work with WCS 1.0.0. - * - * Parameters: - * layer - {} WMS layer that has a matching WCS - * FeatureType at the same server url with the same typename. - * options - {Object} Default properties to be set on the protocol. - * - * Returns: - * {} - */ -OpenLayers.Protocol.WCS.fromWMSLayer = function(layer, options) { - var typeName, featurePrefix; - var param = layer.params["LAYERS"]; - var parts = (OpenLayers.Util.isArray(param) ? param[0] : param).split(":"); - if(parts.length > 1) { - featurePrefix = parts[0]; - } - typeName = parts.pop(); - var protocolOptions = { - url: layer.url, - featureType: typeName, - featurePrefix: featurePrefix, - srsName: layer.projection && layer.projection.getCode() || - layer.map && layer.map.getProjectionObject().getCode(), - version: "1.1.0" - }; - return new OpenLayers.Protocol.WCS(OpenLayers.Util.applyDefaults( - options, protocolOptions - )); -}; - -/** - * Constant: OpenLayers.Protocol.WCS.DEFAULTS - */ -OpenLayers.Protocol.WCS.DEFAULTS = { - "version": "1.0.0" -}; \ No newline at end of file diff --git a/lib/OpenLayers/Protocol/WCS/v1.js b/lib/OpenLayers/Protocol/WCS/v1.js deleted file mode 100644 index 894918461b..0000000000 --- a/lib/OpenLayers/Protocol/WCS/v1.js +++ /dev/null @@ -1,434 +0,0 @@ -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Protocol/WCS.js - */ - -/** - * Class: OpenLayers.Protocol.WCS.v1 - * Abstract class for for v1.0.0 and v1.1.0 protocol. - * - * Inherits from: - * - - */ -OpenLayers.Protocol.WCS.v1 = OpenLayers.Class(OpenLayers.Protocol, { - - /** - * Property: version - * {String} WCS version number. - */ - version: null, - - /** - * Property: srsName - * {String} Name of spatial reference system. Default is "EPSG:4326". - */ - srsName: "EPSG:4326", - - /** - * Property: featureType - * {String} Local feature typeName. - */ - featureType: null, - - /** - * Property: featureNS - * {String} Feature namespace. - */ - featureNS: null, - - /** - * Property: geometryName - * {String} Name of the geometry attribute for features. Default is - * "the_geom" for WCS 1.0, and null for higher versions. - */ - geometryName: "the_geom", - - /** - * Property: schema - * {String} Optional schema location that will be included in the - * schemaLocation attribute value. Note that the feature type schema - * is required for a strict XML validator (on transactions with an - * insert for example), but is *not* required by the WCS specification - * (since the server is supposed to know about feature type schemas). - */ - schema: null, - - /** - * Property: featurePrefix - * {String} Namespace alias for feature type. Default is "feature". - */ - featurePrefix: "feature", - - /** - * Property: formatOptions - * {Object} Optional options for the format. If a format is not provided, - * this property can be used to extend the default format options. - */ - formatOptions: null, - - /** - * Property: readFormat - */ - readFormat: null, - - /** - * Property: readOptions - * {Object} Optional object to pass to format's read. - */ - readOptions: null, - - /** - * Constructor: OpenLayers.Protocol.WCS - * A class for giving layers WCS protocol. - * - * Parameters: - * options - {Object} Optional object whose properties will be set on the - * instance. - * - * Valid options properties: - * url - {String} URL to send requests to (required). - * featureType - {String} Local (without prefix) feature typeName (required). - * featureNS - {String} Feature namespace (required, but can be autodetected - * during the first query if GML is used as readFormat and - * featurePrefix is provided and matches the prefix used by the server - * for this featureType). - * featurePrefix - {String} Feature namespace alias (optional - only used - * for writing if featureNS is provided). Default is 'feature'. - * geometryName - {String} Name of geometry attribute. The default is - * 'the_geom' for WCS 1.0, and null for higher versions. If - * null, it will be set to the name of the first geometry found in the - * first read operation. - * multi - {Boolean} If set to true, geometries will be casted to Multi - * geometries before they are written in a transaction. No casting will - * be done when reading features. - */ - initialize: function(options) { - OpenLayers.Protocol.prototype.initialize.apply(this, [options]); - - if (!options.geometryName && parseFloat(this.format.version) > 1.0) { - this.setGeometryName(null); - } - }, - - /** - * APIMethod: destroy - * Clean up the protocol. - */ - destroy: function() { - if(this.options && !this.options.format) { - this.format.destroy(); - } - this.format = null; - OpenLayers.Protocol.prototype.destroy.apply(this); - }, - - /** - * APIMethod: read - * Construct a request for reading new features. Since WCS splits the - * basic CRUD operations into GetFeature requests (for read) and - * Transactions (for all others), this method does not make use of the - * format's read method (that is only about reading transaction - * responses). - * - * Parameters: - * options - {Object} Options for the read operation, in addition to the - * options set on the instance (options set here will take precedence). - * - * To use a configured protocol to get e.g. a WCS hit count, applications - * could do the following: - * - * (code) - * protocol.read({ - * readOptions: {output: "object"}, - * resultType: "hits", - * maxFeatures: null, - * callback: function(resp) { - * // process resp.numberOfFeatures here - * } - * }); - * (end) - * - * To use a configured protocol to use WCS paging (if supported by the - * server), applications could do the following: - * - * (code) - * protocol.read({ - * startIndex: 0, - * count: 50 - * }); - * (end) - * - * To limit the attributes returned by the GetFeature request, applications - * can use the propertyNames option to specify the properties to include in - * the response: - * - * (code) - * protocol.read({ - * propertyNames: ["DURATION", "INTENSITY"] - * }); - * (end) - */ - read: function(options) { - OpenLayers.Protocol.prototype.read.apply(this, arguments); - options = OpenLayers.Util.extend({}, options); - OpenLayers.Util.applyDefaults(options, this.options || {}); - var response = new OpenLayers.Protocol.Response({requestType: "read"}); - - var data = OpenLayers.Format.XML.prototype.write.apply( - this.format, [this.format.writeNode("wcs:GetFeature", options)] - ); - - response.priv = OpenLayers.Request.POST({ - url: options.url, - callback: this.createCallback(this.handleRead, response, options), - params: options.params, - headers: options.headers, - data: data - }); - - return response; - }, - - /** - * APIMethod: setFeatureType - * Change the feature type on the fly. - * - * Parameters: - * featureType - {String} Local (without prefix) feature typeName. - */ - setFeatureType: function(featureType) { - this.featureType = featureType; - this.format.featureType = featureType; - }, - - /** - * APIMethod: setGeometryName - * Sets the geometryName option after instantiation. - * - * Parameters: - * geometryName - {String} Name of geometry attribute. - */ - setGeometryName: function(geometryName) { - this.geometryName = geometryName; - this.format.geometryName = geometryName; - }, - - /** - * Method: handleRead - * Deal with response from the read request. - * - * Parameters: - * response - {} The response object to pass - * to the user callback. - * options - {Object} The user options passed to the read call. - */ - handleRead: function(response, options) { - options = OpenLayers.Util.extend({}, options); - OpenLayers.Util.applyDefaults(options, this.options); - - if(options.callback) { - var request = response.priv; - if(request.status >= 200 && request.status < 300) { - // success - var result = this.parseResponse(request, options.readOptions); - if (result && result.success !== false) { - if (options.readOptions && options.readOptions.output == "object") { - OpenLayers.Util.extend(response, result); - } else { - response.features = result; - } - response.code = OpenLayers.Protocol.Response.SUCCESS; - } else { - // failure (service exception) - response.code = OpenLayers.Protocol.Response.FAILURE; - response.error = result; - } - } else { - // failure - response.code = OpenLayers.Protocol.Response.FAILURE; - } - options.callback.call(options.scope, response); - } - }, - - /** - * Method: parseResponse - * Read HTTP response body and return features - * - * Parameters: - * request - {XMLHttpRequest} The request object - * options - {Object} Optional object to pass to format's read - * - * Returns: - * {Object} or {Array({})} or - * {} - * An object with a features property, an array of features or a single - * feature. - */ - parseResponse: function(request, options) { - var doc = request.responseXML; - if(!doc || !doc.documentElement) { - doc = request.responseText; - } - if(!doc || doc.length <= 0) { - return null; - } - var result = (this.readFormat !== null) ? this.readFormat.read(doc) : - this.format.read(doc, options); - if (!this.featureNS) { - var format = this.readFormat || this.format; - this.featureNS = format.featureNS; - // no need to auto-configure again on subsequent reads - format.autoConfig = false; - if (!this.geometryName) { - this.setGeometryName(format.geometryName); - } - } - return result; - }, - - /** - * Method: commit - * Given a list of feature, assemble a batch request for update, create, - * and delete transactions. A commit call on the prototype amounts - * to writing a WCS transaction - so the write method on the format - * is used. - * - * Parameters: - * features - {Array()} - * options - {Object} - * - * Valid options properties: - * nativeElements - {Array({Object})} Array of objects with information for writing - * out elements, these objects have vendorId, safeToIgnore and - * value properties. The element is intended to allow access to - * vendor specific capabilities of any particular web feature server or - * datastore. - * - * Returns: - * {} A response object with a features - * property containing any insertIds and a priv property referencing - * the XMLHttpRequest object. - */ - commit: function(features, options) { - - options = OpenLayers.Util.extend({}, options); - OpenLayers.Util.applyDefaults(options, this.options); - - var response = new OpenLayers.Protocol.Response({ - requestType: "commit", - reqFeatures: features - }); - response.priv = OpenLayers.Request.POST({ - url: options.url, - headers: options.headers, - data: this.format.write(features, options), - callback: this.createCallback(this.handleCommit, response, options) - }); - - return response; - }, - - /** - * Method: handleCommit - * Called when the commit request returns. - * - * Parameters: - * response - {} The response object to pass - * to the user callback. - * options - {Object} The user options passed to the commit call. - */ - handleCommit: function(response, options) { - if(options.callback) { - var request = response.priv; - - // ensure that we have an xml doc - var data = request.responseXML; - if(!data || !data.documentElement) { - data = request.responseText; - } - - var obj = this.format.read(data) || {}; - - response.insertIds = obj.insertIds || []; - if (obj.success) { - response.code = OpenLayers.Protocol.Response.SUCCESS; - } else { - response.code = OpenLayers.Protocol.Response.FAILURE; - response.error = obj; - } - options.callback.call(options.scope, response); - } - }, - - /** - * Method: filterDelete - * Send a request that deletes all features by their filter. - * - * Parameters: - * filter - {} filter - */ - filterDelete: function(filter, options) { - options = OpenLayers.Util.extend({}, options); - OpenLayers.Util.applyDefaults(options, this.options); - - var response = new OpenLayers.Protocol.Response({ - requestType: "commit" - }); - - var root = this.format.createElementNSPlus("wcs:Transaction", { - attributes: { - service: "WCS", - version: this.version - } - }); - - var deleteNode = this.format.createElementNSPlus("wcs:Delete", { - attributes: { - typeName: (options.featureNS ? this.featurePrefix + ":" : "") + - options.featureType - } - }); - - if(options.featureNS) { - deleteNode.setAttribute("xmlns:" + this.featurePrefix, options.featureNS); - } - var filterNode = this.format.writeNode("ogc:Filter", filter); - - deleteNode.appendChild(filterNode); - - root.appendChild(deleteNode); - - var data = OpenLayers.Format.XML.prototype.write.apply( - this.format, [root] - ); - - return OpenLayers.Request.POST({ - url: this.url, - callback : options.callback || function(){}, - data: data - }); - - }, - - /** - * Method: abort - * Abort an ongoing request, the response object passed to - * this method must come from this protocol (as a result - * of a read, or commit operation). - * - * Parameters: - * response - {} - */ - abort: function(response) { - if (response) { - response.priv.abort(); - } - }, - - CLASS_NAME: "OpenLayers.Protocol.WCS.v1" -}); diff --git a/lib/OpenLayers/Protocol/WCS/v1_0_0.js b/lib/OpenLayers/Protocol/WCS/v1_0_0.js deleted file mode 100644 index 54a5b8b3a2..0000000000 --- a/lib/OpenLayers/Protocol/WCS/v1_0_0.js +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Protocol/WCS/v1.js - */ - -/** - * Class: OpenLayers.Protocol.WCS.v1_0_0 - * A WCS v1.0.0 protocol for vector layers. Create a new instance with the - * constructor. - * - * Inherits from: - * - - */ -OpenLayers.Protocol.WCS.v1_0_0 = OpenLayers.Class(OpenLayers.Protocol.WCS.v1, { - - /** - * Property: version - * {String} WCS version number. - */ - version: "1.0.0", - - /** - * Constructor: OpenLayers.Protocol.WCS.v1_0_0 - * A class for giving layers WCS v1.0.0 protocol. - * - * Parameters: - * options - {Object} Optional object whose properties will be set on the - * instance. - * - * Valid options properties: - * featureType - {String} Local (without prefix) feature typeName (required). - * featureNS - {String} Feature namespace (optional). - * featurePrefix - {String} Feature namespace alias (optional - only used - * if featureNS is provided). Default is 'feature'. - * geometryName - {String} Name of geometry attribute. Default is 'the_geom'. - */ - - CLASS_NAME: "OpenLayers.Protocol.WCS.v1_0_0" -}); \ No newline at end of file diff --git a/lib/OpenLayers/Protocol/WCS/v1_1_0.js b/lib/OpenLayers/Protocol/WCS/v1_1_0.js deleted file mode 100644 index 05b86f11e8..0000000000 --- a/lib/OpenLayers/Protocol/WCS/v1_1_0.js +++ /dev/null @@ -1,37 +0,0 @@ -/* ====================================================================== - OpenLayers/Protocol/WCS/v1_1_0.js - ====================================================================== */ - -/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the 2-clause BSD license. - * See license.txt in the OpenLayers distribution or repository for the - * full text of the license. */ - -/** - * @requires OpenLayers/Protocol/WCS/v1.js - */ - -/** - * Class: OpenLayers.Protocol.WCS.v1_1_0 - * A WCS v1.1.0 protocol for vector layers. Create a new instance with the - * constructor. - * - * Differences from the v1.0.0 protocol: - * - uses Filter Encoding 1.1.0 instead of 1.0.0 - * - uses GML 3 instead of 2 if no format is provided - * - * Inherits from: - * - - */ -OpenLayers.Protocol.WCS.v1_1_0 = OpenLayers.Class(OpenLayers.Protocol.WCS.v1, { - - /** - * Property: version - * {String} WCS version number. - */ - version: "1.1.0", - - - - CLASS_NAME: "OpenLayers.Protocol.WCS.v1_1_0" -}); From 49ff1b44ea35ff527f0c96d5a7a75a6507ae7fbd Mon Sep 17 00:00:00 2001 From: Christopher Eykamp Date: Thu, 27 Dec 2012 15:43:33 +0100 Subject: [PATCH 050/123] Whitespace --- lib/OpenLayers/Format/WCSCapabilities/v1_1_0.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/OpenLayers/Format/WCSCapabilities/v1_1_0.js b/lib/OpenLayers/Format/WCSCapabilities/v1_1_0.js index cdd1db21f9..a2c3a50d20 100644 --- a/lib/OpenLayers/Format/WCSCapabilities/v1_1_0.js +++ b/lib/OpenLayers/Format/WCSCapabilities/v1_1_0.js @@ -63,30 +63,24 @@ OpenLayers.Format.WCSCapabilities.v1_1_0 = OpenLayers.Class( "Capabilities": function(node, obj) { // In 1.0.0, this was WCS_Capabilties, in 1.1.0, it's just Capabilities this.readChildNodes(node, obj); }, - "Contents": function(node, request) { request.contents = []; this.readChildNodes(node, request.contents); }, - "CoverageSummary": function(node, contents) { var coverageSummary = {}; this.readChildNodes(node, coverageSummary); // Read the summary contents.push(coverageSummary); // Add it to the contents array }, - "Identifier": function(node, coverageSummary) { coverageSummary.identifier = this.getChildValue(node); }, - "Title": function(node, coverageSummary) { coverageSummary.title = this.getChildValue(node); }, - "Abstract": function(node, coverageSummary) { coverageSummary.abstract = this.getChildValue(node); }, - "SupportedCRS": function(node, coverageSummary) { var crs = this.getChildValue(node); if(crs) { @@ -96,7 +90,6 @@ OpenLayers.Format.WCSCapabilities.v1_1_0 = OpenLayers.Class( coverageSummary["supportedCRS"].push(crs); } }, - "SupportedFormat": function(node, coverageSummary) { var format = this.getChildValue(node); if(format) { @@ -107,7 +100,6 @@ OpenLayers.Format.WCSCapabilities.v1_1_0 = OpenLayers.Class( } }, - }, OpenLayers.Format.WCSCapabilities.v1.prototype.readers["wcs"]), "ows": OpenLayers.Format.OWSCommon.v1.prototype.readers["ows"] }, From 88a3091a908177507938f644e42edb8a3ff8d36c Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Thu, 27 Dec 2012 19:49:49 +0100 Subject: [PATCH 051/123] examples: Added example for the EncodedPolyline Format class --- examples/encoded-polyline.html | 47 ++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 examples/encoded-polyline.html diff --git a/examples/encoded-polyline.html b/examples/encoded-polyline.html new file mode 100644 index 0000000000..d084d13148 --- /dev/null +++ b/examples/encoded-polyline.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + +

    Encoded Polyline Example

    + +
    + Encoded Polyline, Google +
    + +

    + Demonstrate the use of the Encoded Polyline format. +

    +
    +
    +

    This example uses the Encoded Polyline format.

    +
    + + From aedafc03362a2dcb3de1900c481ebdd47cab8621 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Thu, 27 Dec 2012 21:36:30 +0100 Subject: [PATCH 052/123] EncodedPolyline: Added geometryType attribute This makes it possible to read polygons or multipoints too. Since the encoded format is just a list of points the reader needs to be told what Feature to create from the encoded list. The example code is edited to reflect that API extension. --- examples/encoded-polyline.html | 2 +- lib/OpenLayers/Format/EncodedPolyline.js | 26 ++++++++++++++- tests/Format/EncodedPolyline.html | 41 ++++++++++++++++++++---- 3 files changed, 61 insertions(+), 8 deletions(-) diff --git a/examples/encoded-polyline.html b/examples/encoded-polyline.html index d084d13148..c40a243201 100644 --- a/examples/encoded-polyline.html +++ b/examples/encoded-polyline.html @@ -22,7 +22,7 @@ map.setCenter(new OpenLayers.LonLat(lon, lat), zoom); var encoded = "m}e`IqvbgAkJqyAoI}w@wTupA}Myb@{CmFsDcEuEgCgFa@oFj@mNzFsFpEiLpQmDxIkMxa@cGpVqE`XqC~Y_Bfw@b@jdAyAzHyCeBRmGlDIp@zHcDpBi@kG`D{@hArHuCtDqBiEhCsCxBfGiBzGcE@{@yF|GtBg@xIsDrB{BcEbAoFnDt@t@|I{BxGiDgABqG`DkAzBbG_A`IoDd@q@cGrD}AhBvGcC~FgDeBbAwF~DjBPrIqDjC}B}DlBmF|DvARbJeDlEuCqCfAiFdExAh@fIwCbEuCgCf@mG~CqBdDvDE|IgDzCsBaE~AgFvD|BV|IsCvG{Et@qCgERaHnCyElEBtCrFMrI_D|DqCyCz@_GlQ~ApEcBdq@es@vx@srApC_Fjc@}y@fCoEfCkCtCvArAvHf@tJCbJeBnHqDrD_E\\qDuC{AeHTaHvBsDbD?lEvPbD~C~Jb@`DaCvDjAStJmEnCwDmAEsGxDoA}B|S}AuEdC}DfEfDNbJmDjCsB}Dj@wG~CyDvJaE~HkHxMwOjMiMjMoK~KeGfEmDdHaMvLka@tNc]pLeSzMcQ|I_UjEcOnCaOh@oG~@iPc@gGqBwEuCmDuCuCeDyA{DHoP|FyIpG{BtF}@lIRzUcAbI_Np\\uHrKsGpOgMtm@o\\bdA_Qvo@uHb_@{Gl^_Df^iB`JyCvHgEnCuCyCzEkCt@rKiC|FyD^sBsD|@cEhDRtBtF_FpNeD}Ag@kFpAgE|Co@pCjECjJkDlEmDqCIqG`C{CvDdBpAfI_BhIgEpCwG_InAmEhDe@~CvDt@hIsAnIsDjEcEWwAqFz@qGfDgChD|DsF|L_AeFdCqBxC|FoAdIoEn@cB{E|A{DlDrC\\rIiCrG_E`@yA}DpAoEbDI|BbFF|IkCrGaEp@eC{CYmF|AkD`DDrCzEHvIkCdGkEEyA{ExAkElDF|BbGm@hJaErDyD_B{@gGzAqElDRlBzGk@pJuDtEaEeAq@wGlBgEnDQ|CbFmAhTqEvAaFcLf@kGpCqMvBaUvA_FvCcD`E`BxAtIaHlK{BgEn@uGjDqApDhE`AxJiA|IkDpCsDuAcBoF~D}K~CiBzIwBtWoJlRoI`VsLzPmKrv@_r@`e@m`@jKcK|IuKpYeWbDmBrDhCNnIyC`EkD}Aa@yFtAyD|CJdBxHiB|GoDEgBuEk@oFf@{ErD]fBvGqG`LuCmBAmF`DgAtCbGHnIoBpG{DnA}BcDt@uFxD]tCbGNnIwCnI{DB_BmEz@sF`EBrB|Ga@xI}BnFsDR{BoDm@oF]wNwDy]gEap@eFu^YmOu@yFmB_FwCuD{DaC}q@oT_Y{Eo_@{E{Oq@}DHoYtCiEtCkBbI~@xIhDnClBoDoAoF}DCeCxFHbJpBzGnDj@hA{E}BsD}DdDo@tJtBnGjDSeA}LuDdCa@lJfC~FrDbA~CeCx@qGoC}DiDvDBbJnDrCpCyCUyFsDYqBfH`AdIlDtBdC}CC{FgCiCqDfDm@rJdAvIbD~EfE[nB{EqAeFgEL{DpEuAfJ~@lJnDtEfEDjCyDNmGsBcEcEr@eCbIf@nKvDtErDiAv@_GsB}DwDr@wIdMcO~OcE~CoEpA{EUaDqDR_GrDl@T`JsDzCwC_Dh@uFzDIvChFFpJ_DzFkEAmBmFIyGnDmB`ChGgAbIaEGYeGxD[nAnHoChF_DkC\\cGlDcAzCdEt@tIcBrHyDdAuBgEn@kG`DyAbDfDp@tI}BlGaE\\qBqE`@mGlDmB`DpDBrIcDbEcEEgCaE]aHxBqEtErA`CpHO~J_CnIyD`CuCeDEsHfC}E`EDlCfGLdK}BvHgE`BsDaCcAqGlA}F`D{AfDvBbB~H]lJyCxFkERkCkE]cHxAoFpDyA~DIvDq@tUiKhFuAnNv@vNCxZoBpE@rd@pEpRRhLi@rPuBvj@sLbNwE|I{@tD~A~CbEzBjHjCpTnCjm@tAnv@u@vv@}DtnAyA`T}Jpd@wNxa@_Srd@iAbHBvIrAbIhDlC`CeDo@gGiDgAwCfEu@dIf@zHlB`H~CpD`CaCaAoFwDRkAhIdBbH|CY?uF_DmByCbENrIhDhD`CkCoAeFyDj@gBfHdA~HhDhBfBiDkAgFaERmBjHz@rIdD|BdAkKsDk@}BbGl@hIbD|BvBeD{@yFoDm@wBnG|@xHlDtA~A_E{AcFwDP_B`HnAlHjDbAxAqE{A{EqDXeBvGxAtHtDLn@yFaCgDcDtBk@zH`CxFpDa@f@cGaCuDgDfAkAhHhAjHdDnBfCmCOkG{ByDkN_PsIwL{^}o@}M}PqZw[_f@gk@sb@o_@wJkFie@yRwSmEuE[qEnA{E\\wCqCDuFxCy@dBtG}BhGmDsAOaFxCoAzC`EHtIeDzDuCoC^iFbDSlBfGkAlIsDdBuBeDz@mEpDdA|@jIwBlGuDBgTqo@kLcm@cEwNqT}y@eIib@kLqc@yLuZcNgb@kOua@gOgYuMwa@}B{EoInDmB`JWfK~AtHpDd@tAqEwBsDwDlCBlIhG_BmCgD}CfEt@fI`EJ^mGeDiB{CzEf@|IjDtA|AyFmBsEsDtAjAlQxCsBu@gGcEj@yAzHvBrG~CqASuGcEOcBtHvBpG`DyAK{GgDsBwCtFfAhIrDDn@eGkCsD}CpEx@~IhDFGaG_EUwAjIzBbGpC_BSwGkb@c`A_CgHsb@scB}S_eAkHa\\gYunAgKy\\qVa`AaHy_@aUcbA}Nwt@{BuHeHmLaC{FyAuGd@mGhDs@pChGg@lJmDhCuC_C_@{EvBgCrDjCpAnI{ApIsDdAmB_DXmFtCwBnDzB~@`JeCbHsDf@gE{Hw@{MiBuLmAmG_XwpAaRoiAyQux@_Ho_@gPkn@o@uHp@gIpDqCpCbGiBfGwDiA]qGjCkD|DvB\\nIqCfEyCqBz@yFjE~@\\vIcD`CmBkEhA{GfEApA~HcC`FwDkAcByFiFoWaHyUcByMiGcYmSoq@uSs_@uh@yx@{O}XyIyPsNy_@yU}g@wb@ss@ui@qw@eJ{JgU}Oko@ko@gEoDeLaFaCuEp@iGtDg@`B`IiCvF{CmBLcGtCkCxDlC`@pJeCxH}DnCaEe@kC}DeBgFoCyCcEl@cBnHvCtEjCaE{AoF}Df@iCvGHtJhDzErD}Aj@mGqBuF{CwBcIcB{HwD_SyRoa@gh@mt@mfAyn@st@sS_X{^qo@}Vii@y\\_h@mM_UgE{L|@uFnEf@lCtHYjJ{CfFwDf@aMiIeDw@sCiBoB}CsDkMgOmw@_Nox@SwG^eHlDyBzBzFwAjG}DS{AoFlB{EzC|DeA`HcDu@R}FpDR^|HeDzAm@kFhDyA~A|GeCtE}BeD~AcFhDrCShIiD|@]oGlDiA~@tH_DnDcBmEfCeDfC~F_BnHeDiAp@iGjDxAH~IkDvBsAkFnCyC|BjGiBlHsD_@NcGrDp@BnIsDdCqBaE|BwD|CnEcAzHsDLg@gG|CiBjCdFSbJsDbBsAoFpCqC`CpF_BpGcDoARgGlDSbBhHyApHyDp@g@oFjDSZjJiClGiD[f@_GvDbBBvJkC~EaCeDrBoEdDzDw@pHiDq@`@iG|DDnAfH}CrDsBqE`CiDdCvFcB`HmDmAj@sGfEp@p@nIiDnCcBqEbCwDfD|NiDnAmAqFZyHy@aH}B{EmVuYqJkNmI_SuNco@eEgBsBrGfCpG`EwDyAqEkChFzB`HrDiBu@mFmD~Bn@jIbELt@sG}CcBcBxGtCdFfDqCg@mGsDb@q@hIrDdElCaEgAuFmD`AYbIrDjD~CkD]kHqBuGwc@}kAyd@stAkHyUa[}dA}Tsq@kGgPkSuc@oa@ubAsP{^{EiNkM{h@uS_qAqEi`@kEmb@_D}b@iXqlDuEib@wHoj@aJ{cA_K{z@cJqo@iGkm@cIqm@aW{eBqEc`@cNqfAwOqfA}DaT_Du_@aFsNsDeAwDxAyCzFYdJjCjFhD{@u@qLoDvBu@|IpB~GpGyEiAeFiDHgBrRfDnDdDsBDaHmCoCmDnCq@fJfC~F|Dq@bAyFyA}DiDOiDfEu@rItA`I|D~BnCiDg@_HgEeAwDvGn@fLvEvBnC_FiAcGkEj@_B`JtC|GlDgCg@wGkEGsBnHzAlIfEHn@qGyH~CjA`JpE^rAiGeCgEcEfBk@fJhD`FvFiKiDqOuBsS_JiuAsCcl@gFap@cGsl@qIog@aMigAqPk|@]yGjCgBvBtFyAdHeEYoBeFz@eFjDxB]tHiD\\q@kFdCeDbDb@dAdHkCjFiD_A{BqOqBaFuHyIaPuJ{CqCmAyE`CuDjCzE{ArG_DuApAeFnA`NeDeAv@yF`E~@p@vIuChEkC{CjA_FrDtBd@tI}C`EkD{BmDiOkJ}q@wHi\\yFkZgDmXKcHpCqDlDbDl@vI}AjIyDvAoA{EnC_DjDfCf@dI{C~EoCgCbFiCCvImDxAgAaFpCsCnCtE_AtHoDIQgGbD}@lBlGiBdGiD{@RoGtDy@~BrF}AhGeDqAHwG~De@hCrHmApHuDIq@iGtC{DtDrCPxIcDrDyC{BRsGzDuA`CrQgDhBuAaFrBeF`ExA~@vIoC|E{CsBRmG|DeA`DtFYfJiD`CuCuCdDkKpDbEHxJiD|DyC_Db@aHnEIxAhTqDbAeB_FxAiGfE]tC`H[bJkD~AkCsEaEwPoMkb@oDkQc^omBmVsyAeA_F}CkAoDjE}ApJHzKbId^xFfa@}BbtAlBxGhE|CdC|GDnIaCzE_Dg@kCkCiBcEuCiByDfAcDjEyAbI`Fj_@iB|UoArIoHb[u\\hpAp@fT_@tJcBlJuChI_Zna@}AzGSfJiB|IcExFwSzMoDbDaElOBlJeA|IkG~QcBfJaHzk@uR|rCaA~H{BvGeBbJwAzYiBnu@_BxGcDx@cB}DwDi_AvAoFdDzBm@bIiDWJcGpDBfAhIqCdFoCkC~@wFxDPzB~Fk@bIyDz@aAsFfCeDhD`CCtIiDzDgEJ}DyAcBsEzBsDfClEoAfHiEp@eCoDxAgEbDhDq@tHgDYd@iFxDdAdAdIqBpGkCeHvDx@l@tI_B~VIlWlBbv@Eta@TrLhDrbBHtgAPjHnBfE|CgBiF{HeCnF]zHZnRxFfnArB`r@v@pJxCbE~CqASgG}DH}B|G^fIfDnAdAmFaCqE{DlA{@lH`CrDvBeDoAiGuDnAShIlCnBrAeFiB{EmDdAaAbIHnUaBtp@mClq@]fm@qDrpB{Ctr@CzJhCdFvCoCkAyFmEz@u@xIfCpEtBaDgBqEaE|BBhIdDtAn@qFcDuBaC`GnArGdDg@I}GkDcBoCfF~@nHtDCZoGiDaBiCxFnAxHfDDJuFyD_AgCjG^tIjB~HhQpg@~EnQnDt@`AwGqCyCuCxEdAhIxDa@ZgHyC{B}BjFzAdHlDaA?_HeDm@kB~FxA~GzD_AGeHaDw@aB|FbBnGlDqAMoHeDw@_BnGlBfGhD}A@gHaD_AyApGvB~FrD}Bg@eHqDOuAfGxAxGrDZbByFiB_FgDxAeBfG{BjPeCrDcEa@yDj@kCtETjIpD~BtAsFyCuFqE^aA|HzCnDpBuFwBsFwDjC`@xHvDl@XkHmDmBoBhGxBlFjCcD{AkFiD`Cl@pHnDBPiHsDqAmBlGxBzEjCcDuAuFyDhBDdInDbAf@qG_D_BgCnGiBfe@u@d]yDjkBiDt`AmFv{A{AjZmG~p@o@lLd@vr@dBfIbDbGzB`Ir@nJ_@nX_DfWuBvIuC|DoDBqBoErA{EbDdCM~HeDz@cAiFdCwBrBtEkA|G_DSM_GxCu@rBrF_@pHyC~B{B{DrA}EbDjAtAzHyCfg@I~HbBdSZvJS|KmBlYiDhZiFzp@gGhf@gJzbAsD`u@cGhmCeDlc@HnJlBnIrDjChBgEmBaEuDlDCvIzCjCfBkEuAeF}DjA{@rIfCrFzCeA]cG_EDuBnH|AdHlDe@@eGsDq@cCdGdAfIrDDT_GsDeAkCrGEhKl@xUtCnj@pDrtAfF|vAnKdwDvFl|AmAtIsDz@{@uFhDeAz@nH{ClE{CkCp@sFnD~@t@bIkCpFmDuANiG`E[pBtGaCvGaE]g@cGbDeCzChD]hIaEjA_BeFlBsE|D`CYrIgElCiCuDlAoFxD|@p@pIcDhEmCaDfA_FpDrBp@jJoJh`@uAtLcNjeBcEdgA{C`d@a@fj@f@~fAMvf@zBhHbE`AhCwEWeHeD}BiDtCe@hIhChG|D]|@mG}ByDiDjCSrIdDrElDkCIsGoDoAiC|F~@tIfEbBdC{Eq@gH{D_BeDxDa@|IdCjHfELbByFoAqGcEm@gDhE}DvPqJtl@sBlIkc@dtA}Yrq@{I`MsSpSoKlO{s@jsAgLxRac@xt@yPfVqRxRyCfHaAjWdDhF~CmB{@}FiEz@o@xIrDxCzBaFgBmFsEbBeA|IlCzGfEc@xAkG}@yGmDkCmE\\mDtDwBhHiLbj@kOpm@_FxVmJf]cNzu@{O`w@me@zsBaPji@mBrIsDlDgCcF|@_IbD}ErPwQdDcFjHgMjZoi@vFyMjK}`@|P{t@tUwiAvDi\\Dg^f@}GbB_FlJ_BvBcDrFyVbNu\\bE{IzCHlAvIyCpGyDDoAwE`C}C`CrFaBjHkDWWyFhDc@`AtHgCfGaEb@uD_B}CuCg@}FjCkC~BhFoAnIeEjC{CyCl@mGlDHxAdHwBlGcDcBp@}FhD~@HdIoDnCqBaE`BsEtCvCy@|HuD?[cGhCkEjRuP~k@if@tZyUxI_JvDX`@lImDtCvBqJrB|GxChDvDg@~DmDvd@el@vOwTtK}RrDbAAnIkE~@{@oFnC}AxBpGaClGwC{BdAuE`DhCc@tIwDR?cGjExAIjJsDzB_AoFxCq@nAlHqCtE{BsDhByDnCfEkAzHsDu@RqFhDh@b@vI}DzC_B{EzF|AkAlI}DCSwGbDk@nBvGkA|H}DGc@yF~Cs@z@dIcD~EgCuCnAgEzCdDHjJsDzCgBkErCmErJlGzDlBfh@hXdg@v]lNfHnjBrbA`iAxq@~a@`Ub\\jOjRpMhMdF|`@tHvLnAb[hAja@lE|SHlJYbb@aFlLl@t\\hFbEnBpVzTd_@lUf`@|OvLxCbRpCfYfJfDfBdAnHsCbGoDmA_AmGrA_E~CxBMdJyDbB_BkE~AiDxCtCSnI{DxAgAaF`CqChJdDzE`@ll@v@p\\u@zDs@f@eFqD]uAbJxC~F`CkDeCyCqC|GrBfIlDsAeA_FwDpDLjKrDzBf@yF{D]eAxIxCzE`CoDwBkEoD|DpAtJzD[@cGoDs@gB~HxC~FtCgCaAwFaEdA{@nJtCvGbDoA{@aGaErAItJvDzCa@iLyChObDlD`E]pc@}LdUmDxi@}InLgCzLg@xRdA|DMpAmEaCcD}DrDeA`Jz@~HjCxDxC]pBqCf@kEcAsFAeFnBwBlDY`EuAzY{NrVgJtd@aUhb@}ZhW{O`SwJhDpBrC~FjDdAnCwBrGkJvIiIb`@qTxKqA`Pu@nKsBbQ}FvPmDvTmJ~CIvG|LlDBpC{BhGkIfXyWhJ{Ev[yMdTmQ|NcJrBoCg@aFyDHmBrIhBhIrDj@pB_DoAkEeE~A_BvI|ApHpCgAm@mF}Dz@cA|IjCxFbDw@NaF_D}AgE~CiBdI`AzIvDtCxD@vZaDrV{@du@e@|q@vB`H{CnDW|D`@zBxFq@nI_DlGqEfDkEIwDsDiEGqBjHpBtGtCwByAyFaElCBjJhD`ATiGyDkAoCxGnAlIrDDHcGiEaAiCdI|AlIrDS?iG}Dy@eClIbBlIzDSHqGsDmBgDlG`@vJrD`CbB}EaCqEcExD@zJrD|BbBwEcCcEeEnDKzJhDbEdDcCm@sFoEl@oAzIjCdFhCaCiAcFcE~@wAhIdCzErBoDgCiDaE`DYzIbDtC~AkE{B}DyDdCq@bJzCxDvBeDyBaEgEfD]hJtCdE~CuBlBkFnDeCfEHdD`EIhIyDvBgBmEtB}CdDdAxAnHkCvGoDsAXyFzCwBh]{FnTiC`k@eL|Eq@brAcP`VyFle@}E`RcDvm@gJdUiFjOsBtg@gL~^{JnKgE|g@gT`J{ArYI~RnAnZnDvXnA|PMlEz@dDzE~@lI{BzG_Dq@`@oFbD|@HjJqDbDoA}DnCwBzBhGgBzHyC_BbAmE~I[bDm@v[_NfRaFrMuEtx@a^dP{EtYkDrOH~LdB`}@~GnMdDlEExAmGMwIoVgjDsHebBgKqxBaG_wAgEgkAoBkf@y@yIc@gI??EI"; - var format = new OpenLayers.Format.EncodedPolyline(); + var format = new OpenLayers.Format.EncodedPolyline({geometryType:"polygon"}); var vector_layer = new OpenLayers.Layer.Vector(); map.addLayer(vector_layer); vector_layer.addFeatures(format.read(encoded)); diff --git a/lib/OpenLayers/Format/EncodedPolyline.js b/lib/OpenLayers/Format/EncodedPolyline.js index 237782b7f7..b09bd2b39e 100644 --- a/lib/OpenLayers/Format/EncodedPolyline.js +++ b/lib/OpenLayers/Format/EncodedPolyline.js @@ -18,6 +18,13 @@ */ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { + /** + * APIProperty: geometryType + * {String} Geometry type to output. One of: linestring (default), + * linearring, multipoint or polygon + */ + geometryType: "linestring", + /** * Constructor: OpenLayers.Format.EncodedPolyline * Create a new parser for encoded polylines @@ -44,6 +51,16 @@ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { * {} A vector feature with a linestring. */ read: function(encoded) { + var geomType; + if (this.geometryType == "linestring") + geomType = OpenLayers.Geometry.LineString; + else if (this.geometryType == "linearring") + geomType = OpenLayers.Geometry.LinearRing; + else if (this.geometryType == "multipoint") + geomType = OpenLayers.Geometry.MultiPoint; + else if (this.geometryType != "polygon") + return null; + var points = new Array(); var lat = 0; @@ -76,8 +93,15 @@ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { points.push(new OpenLayers.Geometry.Point(lon * 1e-5, lat * 1e-5)); } + if (this.geometryType == "polygon") + return new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.Polygon([ + new OpenLayers.Geometry.LinearRing(points) + ]) + ); + return new OpenLayers.Feature.Vector( - new OpenLayers.Geometry.LineString(points) + new geomType(points) ); }, diff --git a/tests/Format/EncodedPolyline.html b/tests/Format/EncodedPolyline.html index 29e0a65709..10f2487347 100644 --- a/tests/Format/EncodedPolyline.html +++ b/tests/Format/EncodedPolyline.html @@ -3,11 +3,27 @@ From 2c5d4c75d43da3c00c112b3ab3a8ec97ba7ff021 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Thu, 27 Dec 2012 22:10:51 +0100 Subject: [PATCH 053/123] EncodedPolyline: Merged duplicate code in read() method This patch also prepares the code for making it possible to read encoded strings with multi-dimensional points. --- lib/OpenLayers/Format/EncodedPolyline.js | 38 +++++++++--------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/lib/OpenLayers/Format/EncodedPolyline.js b/lib/OpenLayers/Format/EncodedPolyline.js index b09bd2b39e..a71b0a449b 100644 --- a/lib/OpenLayers/Format/EncodedPolyline.js +++ b/lib/OpenLayers/Format/EncodedPolyline.js @@ -62,35 +62,25 @@ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { return null; var points = new Array(); - - var lat = 0; - var lon = 0; + var point = new Array(0, 0); for (var i = 0; i < encoded.length;) { - var b; - var result = 0; - var shift = 0; + for (var dim = 0; dim < 2; ++dim) { + var result = 0; + var shift = 0; - do { - b = encoded.charCodeAt(i++) - 63; - result |= (b & 0x1f) << shift; - shift += 5; - } while (b >= 0x20); + var b; + do { + b = encoded.charCodeAt(i++) - 63; + result |= (b & 0x1f) << shift; + shift += 5; + } while (b >= 0x20); - lat += ((result & 1) ? ~(result >> 1) : (result >> 1)); + point[dim] += ((result & 1) ? ~(result >> 1) : (result >> 1)); + } - result = 0; - shift = 0; - - do { - b = encoded.charCodeAt(i++) - 63; - result |= (b & 0x1f) << shift; - shift += 5; - } while (b >= 0x20); - - lon += ((result & 1) ? ~(result >> 1) : (result >> 1)); - - points.push(new OpenLayers.Geometry.Point(lon * 1e-5, lat * 1e-5)); + points.push(new OpenLayers.Geometry.Point(point[1] * 1e-5, + point[0] * 1e-5)); } if (this.geometryType == "polygon") From c118d9884da0f52279adcddf347378615865d822 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Thu, 27 Dec 2012 23:07:31 +0100 Subject: [PATCH 054/123] EncodedPolyline: Extracted universal decode(encoded, dims) method --- lib/OpenLayers/Format/EncodedPolyline.js | 57 ++++++++++++++++++------ tests/Format/EncodedPolyline.html | 30 +++++++++++-- 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/lib/OpenLayers/Format/EncodedPolyline.js b/lib/OpenLayers/Format/EncodedPolyline.js index a71b0a449b..5c7b68c221 100644 --- a/lib/OpenLayers/Format/EncodedPolyline.js +++ b/lib/OpenLayers/Format/EncodedPolyline.js @@ -61,11 +61,50 @@ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { else if (this.geometryType != "polygon") return null; + var points = this.decode(encoded, 2); + var pointGeometries = new Array(); + for (i in points) { + var point = points[i]; + pointGeometries.push( + new OpenLayers.Geometry.Point(point[1] * 1e-5, point[0] * 1e-5) + ); + } + + if (this.geometryType == "polygon") + return new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.Polygon([ + new OpenLayers.Geometry.LinearRing(pointGeometries) + ]) + ); + + return new OpenLayers.Feature.Vector( + new geomType(pointGeometries) + ); + }, + + /** + * Method: decode + * Deserialize an encoded string and return an array of n-dimensional + * points. + * + * Parameters: + * encoded - {String} An encoded string + * dims - {int} The dimension of the points that are returned + * + * Returns: + * {Array(Array(int))} An array containing n-dimensional arrays of + * coordinates. + */ + decode: function(encoded, dims) { var points = new Array(); - var point = new Array(0, 0); + var point = new Array(dims); + + // Reset the point array + for (var i = 0; i < point.length; ++i) + point[i] = 0; for (var i = 0; i < encoded.length;) { - for (var dim = 0; dim < 2; ++dim) { + for (var dim = 0; dim < dims; ++dim) { var result = 0; var shift = 0; @@ -79,20 +118,10 @@ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { point[dim] += ((result & 1) ? ~(result >> 1) : (result >> 1)); } - points.push(new OpenLayers.Geometry.Point(point[1] * 1e-5, - point[0] * 1e-5)); + points.push(point.slice(0)); } - if (this.geometryType == "polygon") - return new OpenLayers.Feature.Vector( - new OpenLayers.Geometry.Polygon([ - new OpenLayers.Geometry.LinearRing(points) - ]) - ); - - return new OpenLayers.Feature.Vector( - new geomType(points) - ); + return points; }, CLASS_NAME: "OpenLayers.Format.EncodedPolyline" diff --git a/tests/Format/EncodedPolyline.html b/tests/Format/EncodedPolyline.html index 10f2487347..9ad7dbd726 100644 --- a/tests/Format/EncodedPolyline.html +++ b/tests/Format/EncodedPolyline.html @@ -3,10 +3,19 @@ From 8651e05e75468db6f36a3810da23ef2ef18951e1 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Thu, 27 Dec 2012 23:19:44 +0100 Subject: [PATCH 055/123] EncodedPolyline: Allow setting geometryType to "point --- lib/OpenLayers/Format/EncodedPolyline.js | 10 ++++++++-- tests/Format/EncodedPolyline.html | 6 +++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/OpenLayers/Format/EncodedPolyline.js b/lib/OpenLayers/Format/EncodedPolyline.js index 5c7b68c221..289c2aa8ef 100644 --- a/lib/OpenLayers/Format/EncodedPolyline.js +++ b/lib/OpenLayers/Format/EncodedPolyline.js @@ -21,7 +21,8 @@ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { /** * APIProperty: geometryType * {String} Geometry type to output. One of: linestring (default), - * linearring, multipoint or polygon + * linearring, point, multipoint or polygon. If the geometryType is + * point, only the first point of the string is returned. */ geometryType: "linestring", @@ -58,7 +59,7 @@ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { geomType = OpenLayers.Geometry.LinearRing; else if (this.geometryType == "multipoint") geomType = OpenLayers.Geometry.MultiPoint; - else if (this.geometryType != "polygon") + else if (this.geometryType != "point" && this.geometryType != "polygon") return null; var points = this.decode(encoded, 2); @@ -70,6 +71,11 @@ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { ); } + if (this.geometryType == "point") + return new OpenLayers.Feature.Vector( + pointGeometries[0] + ); + if (this.geometryType == "polygon") return new OpenLayers.Feature.Vector( new OpenLayers.Geometry.Polygon([ diff --git a/tests/Format/EncodedPolyline.html b/tests/Format/EncodedPolyline.html index 9ad7dbd726..b1692ba848 100644 --- a/tests/Format/EncodedPolyline.html +++ b/tests/Format/EncodedPolyline.html @@ -51,7 +51,7 @@ } function test_Format_EncodedPolyline_read(t) { - t.plan(4); + t.plan(5); var format = new OpenLayers.Format.EncodedPolyline(); @@ -71,6 +71,10 @@ format.geometryType = "polygon"; t.ok(polygon.geometry.equals(format.read(encoded).geometry), "format correctly reads encoded polygon"); + + format.geometryType = "point"; + t.ok(points[0].equals(format.read(encoded).geometry), + "format correctly reads encoded point"); } function test_Format_EncodedPolyline_decode(t) { From 510d42b12ffd567791fa7d66c6e62ebf250fd151 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Fri, 28 Dec 2012 01:31:24 +0100 Subject: [PATCH 056/123] EncodedPolyline: Added encode() method The write() method will follow in the next commit. --- lib/OpenLayers/Format/EncodedPolyline.js | 75 ++++++++++++++++++++++++ tests/Format/EncodedPolyline.html | 8 +++ 2 files changed, 83 insertions(+) diff --git a/lib/OpenLayers/Format/EncodedPolyline.js b/lib/OpenLayers/Format/EncodedPolyline.js index 289c2aa8ef..c901d7c796 100644 --- a/lib/OpenLayers/Format/EncodedPolyline.js +++ b/lib/OpenLayers/Format/EncodedPolyline.js @@ -130,5 +130,80 @@ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { return points; }, + /** + * Method: encode + * Serialize an array of n-dimensional points and return an encoded string + * + * Parameters: + * points - {Array(Array(int))} An array containing n-dimensional + * arrays of coordinates + * dims - {int} The dimension of the points that should be read + * + * Returns: + * {String} An encoded string + */ + encode: function (points, dims) { + var encoded_points = ""; + + var lastPoint = new Array(dims); + for (var i = 0; i < lastPoint.length; ++i) + lastPoint[i] = 0; + + for (var i = 0; i < points.length; i++) { + var point = points[i]; + + for (var dim = 0; dim < lastPoint.length; ++dim) { + var delta = point[dim] - lastPoint[dim]; + encoded_points += this.encodeSignedNumber(delta); + } + + lastPoint = point; + } + return encoded_points; + }, + + /** + * Method: encodeSignedNumber + * Encode one single signed integer and return an encoded string + * + * Parameters: + * num - {int} A signed integer that should be encoded + * + * Returns: + * {String} An encoded string + */ + encodeSignedNumber: function (num) { + var sgn_num = num << 1; + if (num < 0) + sgn_num = ~(sgn_num); + + return this.encodeNumber(sgn_num); + }, + + /** + * Method: encodeNumber + * Encode one single unsigned integer and return an encoded string + * + * encodeSignedNumber should be used instead of using this method directly! + * + * Parameters: + * num - {int} An unsigned integer that should be encoded + * + * Returns: + * {String} An encoded string + */ + encodeNumber: function (num) { + var encodeString = ""; + var value; + while (num >= 0x20) { + value = (0x20 | (num & 0x1f)) + 63; + encodeString += (String.fromCharCode(value)); + num >>= 5; + } + value = num + 63; + encodeString += (String.fromCharCode(value)); + return encodeString; + }, + CLASS_NAME: "OpenLayers.Format.EncodedPolyline" }); diff --git a/tests/Format/EncodedPolyline.html b/tests/Format/EncodedPolyline.html index b1692ba848..785b56df41 100644 --- a/tests/Format/EncodedPolyline.html +++ b/tests/Format/EncodedPolyline.html @@ -91,6 +91,14 @@ } } + function test_Format_EncodedPolyline_encode(t) { + t.plan(1); + + var format = new OpenLayers.Format.EncodedPolyline(); + + t.eq(format.encode(basePoints, 2), encoded); + } + From 06409da72e1c453a100d05ce188e44f3547ae820 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Fri, 28 Dec 2012 19:14:30 +0100 Subject: [PATCH 057/123] EncodedPolyline: Added APIMethod keywords to documentation --- lib/OpenLayers/Format/EncodedPolyline.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/OpenLayers/Format/EncodedPolyline.js b/lib/OpenLayers/Format/EncodedPolyline.js index c901d7c796..53050f294e 100644 --- a/lib/OpenLayers/Format/EncodedPolyline.js +++ b/lib/OpenLayers/Format/EncodedPolyline.js @@ -42,7 +42,7 @@ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { }, /** - * Method: read + * APIMethod: read * Deserialize an encoded polyline string and return a vector feature. * * Parameters: @@ -89,7 +89,7 @@ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { }, /** - * Method: decode + * APIMethod: decode * Deserialize an encoded string and return an array of n-dimensional * points. * @@ -131,7 +131,7 @@ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { }, /** - * Method: encode + * APIMethod: encode * Serialize an array of n-dimensional points and return an encoded string * * Parameters: From 60a02e343bbceb91a094f387799b816524bc6f96 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Fri, 28 Dec 2012 19:29:52 +0100 Subject: [PATCH 058/123] WKT: Added APIMethod keywords to documentation --- lib/OpenLayers/Format/WKT.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/OpenLayers/Format/WKT.js b/lib/OpenLayers/Format/WKT.js index 33cdd2464b..b2c13e15c7 100644 --- a/lib/OpenLayers/Format/WKT.js +++ b/lib/OpenLayers/Format/WKT.js @@ -41,7 +41,7 @@ OpenLayers.Format.WKT = OpenLayers.Class(OpenLayers.Format, { }, /** - * Method: read + * APIMethod: read * Deserialize a WKT string and return a vector feature or an * array of vector features. Supports WKT for POINT, MULTIPOINT, * LINESTRING, MULTILINESTRING, POLYGON, MULTIPOLYGON, and @@ -84,7 +84,7 @@ OpenLayers.Format.WKT = OpenLayers.Class(OpenLayers.Format, { }, /** - * Method: write + * APIMethod: write * Serialize a feature or array of features into a WKT string. * * Parameters: From 69d759635f3d57caa86f4763c5a86992cc2660f3 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Fri, 28 Dec 2012 19:30:10 +0100 Subject: [PATCH 059/123] WKT: Removed unused variables from write() method --- lib/OpenLayers/Format/WKT.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/OpenLayers/Format/WKT.js b/lib/OpenLayers/Format/WKT.js index b2c13e15c7..07beddb0d6 100644 --- a/lib/OpenLayers/Format/WKT.js +++ b/lib/OpenLayers/Format/WKT.js @@ -95,7 +95,7 @@ OpenLayers.Format.WKT = OpenLayers.Class(OpenLayers.Format, { * {String} The WKT string representation of the input geometries */ write: function(features) { - var collection, geometry, type, data, isCollection; + var collection, geometry, isCollection; if (features.constructor == Array) { collection = features; isCollection = true; From 06bd07ff8de423b1d6f33ca67038ce3b4fc61b3a Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Fri, 28 Dec 2012 20:24:57 +0100 Subject: [PATCH 060/123] EncodedPolyline: Added write() method --- lib/OpenLayers/Format/EncodedPolyline.js | 45 ++++++++++++++++++++++++ tests/Format/EncodedPolyline.html | 27 ++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/lib/OpenLayers/Format/EncodedPolyline.js b/lib/OpenLayers/Format/EncodedPolyline.js index 53050f294e..1255eb1c91 100644 --- a/lib/OpenLayers/Format/EncodedPolyline.js +++ b/lib/OpenLayers/Format/EncodedPolyline.js @@ -130,6 +130,51 @@ OpenLayers.Format.EncodedPolyline = OpenLayers.Class(OpenLayers.Format, { return points; }, + /** + * APIMethod: write + * Serialize a feature or array of features into a WKT string. + * + * Parameters: + * features - {|Array} A feature or array of + * features + * + * Returns: + * {String} The WKT string representation of the input geometries + */ + write: function(features) { + var feature; + if (features.constructor == Array) + feature = features[0]; + else + feature = features; + + var geometry = feature.geometry; + var type = geometry.CLASS_NAME.split('.')[2].toLowerCase(); + + var pointGeometries; + if (type == "point") + pointGeometries = new Array(geometry); + else if (type == "linestring" || + type == "linearring" || + type == "multipoint") + pointGeometries = geometry.components; + else if (type == "polygon") + pointGeometries = geometry.components[0].components; + else + return null; + + var points = new Array(); + for (var i in pointGeometries) { + var pointGeometry = pointGeometries[i]; + var point = [Math.round(pointGeometry.y * 1e5), + Math.round(pointGeometry.x * 1e5)]; + points.push(point); + } + + var result = this.encode(points, 2); + return result; + }, + /** * APIMethod: encode * Serialize an array of n-dimensional points and return an encoded string diff --git a/tests/Format/EncodedPolyline.html b/tests/Format/EncodedPolyline.html index 785b56df41..1a93a41afa 100644 --- a/tests/Format/EncodedPolyline.html +++ b/tests/Format/EncodedPolyline.html @@ -18,6 +18,8 @@ basePoints[2][0] * 1e-5) ]; + var singlePoint = new OpenLayers.Feature.Vector(points[0]); + var linestring = new OpenLayers.Feature.Vector( new OpenLayers.Geometry.LineString(points) ); @@ -91,6 +93,31 @@ } } + function test_Format_EncodedPolyline_write(t) { + t.plan(5); + + var format = new OpenLayers.Format.EncodedPolyline(); + + t.eq(format.write(linestring), encoded, + "format correctly writes encoded polyline"); + + t.eq(format.write(multipoint), encoded, + "format correctly writes encoded multipoint"); + + // Different output than encoded, + // because polygon closing point is included + t.eq(format.write(linearring), + "_p~iF~ps|U_ulLnnqC_mqNvxq`@~b_\\ghde@", + "format correctly writes encoded linearring"); + + t.eq(format.write(polygon), + "_p~iF~ps|U_ulLnnqC_mqNvxq`@~b_\\ghde@", + "format correctly writes encoded polygon"); + + t.eq(format.write(singlePoint), "_p~iF~ps|U", + "format correctly writes encoded point"); + } + function test_Format_EncodedPolyline_encode(t) { t.plan(1); From 0915fb72a2e6f48a343fe9ac6121c1a2a42c0321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Brunner?= Date: Fri, 14 Sep 2012 17:16:46 +0200 Subject: [PATCH 061/123] Add RESTful compatibility support --- lib/OpenLayers/Format/WMTSCapabilities.js | 9 ++- tests/Format/WMTSCapabilities/v1_0_0.html | 83 ++++++++++++++++++++++- 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/lib/OpenLayers/Format/WMTSCapabilities.js b/lib/OpenLayers/Format/WMTSCapabilities.js index b23bf2bd66..29b8af7ac1 100644 --- a/lib/OpenLayers/Format/WMTSCapabilities.js +++ b/lib/OpenLayers/Format/WMTSCapabilities.js @@ -139,8 +139,13 @@ OpenLayers.Format.WMTSCapabilities = OpenLayers.Class(OpenLayers.Format.XML.Vers // Get first get method if (http.get[0].constraints) { var constraints = http.get[0].constraints; - if (!constraints.GetEncoding.allowedValues.KVP && - constraints.GetEncoding.allowedValues.REST) { + var allowedValues = constraints.GetEncoding.allowedValues; + + // The OGC documentation is not clear if we should use + // REST or RESTful, ArcGis use RESTful, + // and OpenLayers use REST. + if (!allowedValues.KVP && + (allowedValues.REST || allowedValues.RESTful)) { requestEncoding = "REST"; } } diff --git a/tests/Format/WMTSCapabilities/v1_0_0.html b/tests/Format/WMTSCapabilities/v1_0_0.html index c5229df4c1..f4fadeb614 100644 --- a/tests/Format/WMTSCapabilities/v1_0_0.html +++ b/tests/Format/WMTSCapabilities/v1_0_0.html @@ -150,7 +150,7 @@ } function test_createLayer(t) { - t.plan(42); + t.plan(43); var format = new OpenLayers.Format.WMTSCapabilities(); @@ -308,6 +308,15 @@ requestEncoding: 'KVP' }); t.eq(layer.url[0], "http://wmts.geo.admin.ch/kvp", "correct kvp url 2"); + + // test RESTfull + xml = document.getElementById("arcgis").firstChild.nodeValue; + doc = new OpenLayers.Format.XML().read(xml); + caps = format.read(doc); + layer = format.createLayer(caps, { + layer: "WorldTimeZones" + }); + t.eq(layer.requestEncoding, "REST", "correct requestEncoding (in RESTfull)"); } function test_parse_projection(t) { @@ -875,6 +884,78 @@ http://schemas.opengis.net/wmts/1.0/examples/wmtsGetCapabilities_response.xml --> +