From e970151067ae63fb5ecc550b8aa06b8c296b9712 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Wed, 24 Nov 2010 10:44:01 +0000 Subject: [PATCH] new "immediate" option to enable live measuring while moving the mouse. p=patzi,me r=me (closes #2935) git-svn-id: http://svn.openlayers.org/trunk/openlayers@10917 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf --- examples/measure.html | 15 +++- lib/OpenLayers/Control/Measure.js | 49 +++++++++-- tests/Control/Measure.html | 136 ++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+), 6 deletions(-) diff --git a/examples/measure.html b/examples/measure.html index 698c75730f..d283e8c297 100644 --- a/examples/measure.html +++ b/examples/measure.html @@ -132,6 +132,13 @@ control.geodesic = element.checked; } } + + function toggleImmediate(element) { + for(key in measureControls) { + var control = measureControls[key]; + control.setImmediate(element.checked); + } + } @@ -164,13 +171,19 @@ +
  • + + +
  • Note that the geometries drawn are planar geometries and the metrics returned by the measure control are planar measures by default. If your map is in a geographic projection or you have the appropriate projection definitions to transform your geometries into geographic coordinates, you can set the "geodesic" property of the control - to true to calculate geodesic measures instead of planar measures.

    + to true to calculate geodesic measures instead of planar measures. + Also you have the possibility to set the "immediate" property to true + to get a new calculated value once the mouse has been mooved.

    diff --git a/lib/OpenLayers/Control/Measure.js b/lib/OpenLayers/Control/Measure.js index 8fa858e557..d51d7f3189 100644 --- a/lib/OpenLayers/Control/Measure.js +++ b/lib/OpenLayers/Control/Measure.js @@ -33,7 +33,8 @@ OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, { * will receive an event with measure, units, order, and geometry * properties. * measurepartial - Triggered when a new point is added to the - * measurement sketch. Listeners receive an event with measure, + * measurement sketch or if the property is true and the + * measurement sketch is modified. Listeners receive an event with measure, * units, order, and geometry. */ EVENT_TYPES: ['measure', 'measurepartial'], @@ -103,6 +104,14 @@ OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, { */ persist: false, + /** + * APIProperty: immediate + * {Boolean} Activates the immediate measurement so that the "measurepartial" + * event is also fired once the measurement sketch is modified. + * Default is false. + */ + immediate : false, + /** * Constructor: OpenLayers.Control.Measure * @@ -117,10 +126,12 @@ OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, { OpenLayers.Control.prototype.EVENT_TYPES ); OpenLayers.Control.prototype.initialize.apply(this, [options]); - this.callbacks = OpenLayers.Util.extend( - {done: this.measureComplete, point: this.measurePartial}, - this.callbacks - ); + var callbacks = {done: this.measureComplete, + point: this.measurePartial}; + if (this.immediate){ + callbacks.modify = this.measureImmediate; + } + this.callbacks = OpenLayers.Util.extend(callbacks, this.callbacks); // let the handler options override, so old code that passes 'persist' // directly to the handler does not need an update @@ -147,6 +158,20 @@ OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, { this.cancelDelay(); this.handler.cancel(); }, + + /** + * APIMethod: setImmediate + * Set is true, the temporary + * sketch will be erased. + */ + setImmediate: function(immediate) { + this.immediate = immediate; + if (this.immediate){ + this.callbacks.modify = this.measureImmediate; + } else { + delete this.callbacks.modify; + } + }, /** * Method: updateHandler @@ -205,6 +230,20 @@ OpenLayers.Control.Measure = OpenLayers.Class(OpenLayers.Control, { } }, + /** + * Method: measureImmediate + * Called each time the measurement sketch is modified. + * + * Parameters: point - {} The point at the + * mouseposition. feature - {} The sketch feature. + */ + measureImmediate : function(point, feature) { + if (this.delayedTrigger === null && + !this.handler.freehandMode(this.handler.evt)) { + this.measure(feature.geometry, "measurepartial"); + } + }, + /** * Method: cancelDelay * Cancels the delay measurement that measurePartial began. diff --git a/tests/Control/Measure.html b/tests/Control/Measure.html index ae3d0e5e27..e8eaa7091e 100644 --- a/tests/Control/Measure.html +++ b/tests/Control/Measure.html @@ -222,6 +222,142 @@ ); } + + function test_immediate(t) { + t.plan(29); + + var map = new OpenLayers.Map({ + div: "map", + units: "m", + resolutions: [1], + layers: [ + new OpenLayers.Layer(null, { + isBaseLayer: true + }) + ], + center: new OpenLayers.LonLat(0, 0) + }); + + var log = []; + var control = new OpenLayers.Control.Measure( + OpenLayers.Handler.Path, { + persist: true, + immediate: true, + eventListeners: { + measurepartial: function(evt) { + log.push(evt); + }, + measure: function(evt){ + log.push(evt); + } + } + } + ); + map.addControl(control); + control.activate(); + + // convenience function to trigger mouse events + function trigger(type, x, y) { + map.events.triggerEvent(type, { + xy: new OpenLayers.Pixel(x, y) + }) + }; + + // delay in seconds + var delay = control.partialDelay / 1000; + + // a) establish first point + trigger("mousedown", 0, 0); + trigger("mouseup", 0, 0); + + // move 10 pixels + trigger("mousemove", 0, 10); + + t.eq(log.length, 0, "a) no event fired yet"); + + t.delay_call( + delay, function() { + // confirm measurepartial is fired + t.eq(log.length, 1, "a) event logged"); + t.eq(log[0].type, "measurepartial", "a) correct type"); + // mousemove within the partialDelay fires no event, so the + // measure below is the one of the initial point + t.eq(log[0].measure, 0, "a) correct measure"); + + // b) move 10 pixels + trigger("mousemove", 0, 20); + // c) move 10 pixels again + trigger("mousemove", 0, 30); + + // confirm measurepartial is fired 2 times + t.eq(log.length, 3, "b) event logged"); + t.eq(log[1].type, "measurepartial", "b) correct type"); + t.eq(log[1].measure, 20, "b) correct measure"); + t.eq(log[2].type, "measurepartial", "c) correct type"); + t.eq(log[2].measure, 30, "c) correct measure"); + + // d) switch immediate measurement off + control.setImmediate(false); + t.eq(control.immediate, false, "d) immediate is false"); + + // e) move 10 pixels and click + trigger("mousemove", 0, 40); + trigger("mousedown", 0, 40); + trigger("mouseup", 0, 40); + // confirm measurepartial is not fired before delay + t.eq(log.length, 3, "e) no event fired yet") + }, + // wait for delay then confirm event was logged + delay, function() { + t.eq(log.length, 4, "e) event logged") + t.eq(log[3].type, "measurepartial", "e) correct type"); + t.eq(log[3].measure, 40, "e) correct measure"); + + // f) switch immediate measurement on + control.setImmediate(true); + t.eq(control.immediate, true, "f) immediate is true"); + + // g) move 10 pixels + trigger("mousemove", 0, 50); + }, + delay, function() { + t.eq(log.length, 5, "g) event logged"); + t.eq(log[4].type, "measurepartial", "g) correct type"); + t.eq(log[4].measure, 50, "g) correct measure"); + + // h) move 10 pixels + trigger("mousemove", 0, 60); + + t.eq(log.length, 6, "h) event logged"); + t.eq(log[5].type, "measurepartial", "h) correct type"); + t.eq(log[5].measure, 60, "h) correct measure"); + + // i) double click to finish + trigger("mousedown", 0, 60); + trigger("mouseup", 0, 60); + t.eq(log.length, 6, "i) no event fired yet"); + }, + delay, function() { + t.eq(log.length, 7, "i) event logged"); + t.eq(log[6].type, "measurepartial", "i) correct type"); + t.eq(log[6].measure, 60, "i) correct measure"); + + trigger("dblclick", 0, 60); + t.eq(log.length, 8, "i) event logged"); + t.eq(log[7].type, "measure", "i) correct type"); + t.eq(log[7].measure, 60, "i) correct measure"); + // clear log + log = []; + + // j) clean up + map.destroy(); + // wait for delay and confirm event not logged + }, + delay, function() { + t.eq(log.length, 0, "j) no event fired after destroy"); + } + ); + }