diff --git a/examples/drag-features.html b/examples/drag-features.html new file mode 100644 index 0000000000..109afa0074 --- /dev/null +++ b/examples/drag-features.html @@ -0,0 +1,51 @@ + + + + + + + + + + + Drag features example + + + + + +
+ +
+
+
+
+
+ +
+ +
+

Drag features example

+

Example of a drag features interaction.

+
+

See the drag-features.js source to see how this is done.

+
+
drag, feature, vector, editing
+
+ +
+ +
+ + + + + + + diff --git a/examples/drag-features.js b/examples/drag-features.js new file mode 100644 index 0000000000..faff5ae42b --- /dev/null +++ b/examples/drag-features.js @@ -0,0 +1,192 @@ +goog.require('ol.Feature'); +goog.require('ol.Map'); +goog.require('ol.View'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.Point'); +goog.require('ol.geom.Polygon'); +goog.require('ol.interaction'); +goog.require('ol.interaction.Pointer'); +goog.require('ol.layer.Tile'); +goog.require('ol.layer.Vector'); +goog.require('ol.source.TileJSON'); +goog.require('ol.source.Vector'); +goog.require('ol.style.Fill'); +goog.require('ol.style.Icon'); +goog.require('ol.style.Stroke'); +goog.require('ol.style.Style'); + + +/** + * Define a namespace for the application. + */ +window.app = {}; +var app = window.app; + + + +/** + * @constructor + * @extends {ol.interaction.Pointer} + */ +app.Drag = function() { + + ol.interaction.Pointer.call(this, { + handleDownEvent: app.Drag.prototype.handleDownEvent, + handleDragEvent: app.Drag.prototype.handleDragEvent, + handleMoveEvent: app.Drag.prototype.handleMoveEvent, + handleUpEvent: app.Drag.prototype.handleUpEvent + }); + + /** + * @type {ol.Pixel} + * @private + */ + this.coordinate_ = null; + + /** + * @type {string|undefined} + * @private + */ + this.cursor_ = 'pointer'; + + /** + * @type {ol.Feature} + * @private + */ + this.feature_ = null; + + /** + * @type {string|undefined} + * @private + */ + this.previousCursor_ = undefined; + +}; +ol.inherits(app.Drag, ol.interaction.Pointer); + + +/** + * @param {ol.MapBrowserEvent} evt Map browser event. + * @return {boolean} `true` to start the drag sequence. + */ +app.Drag.prototype.handleDownEvent = function(evt) { + var map = evt.map; + + var feature = map.forEachFeatureAtPixel(evt.pixel, + function(feature, layer) { + return feature; + }); + + if (feature) { + this.coordinate_ = evt.coordinate; + this.feature_ = feature; + } + + return !!feature; +}; + + +/** + * @param {ol.MapBrowserEvent} evt Map browser event. + */ +app.Drag.prototype.handleDragEvent = function(evt) { + var map = evt.map; + + var feature = map.forEachFeatureAtPixel(evt.pixel, + function(feature, layer) { + return feature; + }); + + var deltaX = evt.coordinate[0] - this.coordinate_[0]; + var deltaY = evt.coordinate[1] - this.coordinate_[1]; + + var geometry = /** @type {ol.geom.SimpleGeometry} */ + (this.feature_.getGeometry()); + geometry.translate(deltaX, deltaY); + + this.coordinate_[0] = evt.coordinate[0]; + this.coordinate_[1] = evt.coordinate[1]; +}; + + +/** + * @param {ol.MapBrowserEvent} evt Event. + */ +app.Drag.prototype.handleMoveEvent = function(evt) { + if (this.cursor_) { + var map = evt.map; + var feature = map.forEachFeatureAtPixel(evt.pixel, + function(feature, layer) { + return feature; + }); + var element = evt.map.getTargetElement(); + if (feature) { + if (element.style.cursor != this.cursor_) { + this.previousCursor_ = element.style.cursor; + element.style.cursor = this.cursor_; + } + } else if (this.previousCursor_ !== undefined) { + element.style.cursor = this.previousCursor_; + this.previousCursor_ = undefined; + } + } +}; + + +/** + * @param {ol.MapBrowserEvent} evt Map browser event. + * @return {boolean} `false` to stop the drag sequence. + */ +app.Drag.prototype.handleUpEvent = function(evt) { + this.coordinate_ = null; + this.feature_ = null; + return false; +}; + + +var pointFeature = new ol.Feature(new ol.geom.Point([0, 0])); + +var lineFeature = new ol.Feature( + new ol.geom.LineString([[-1e7, 1e6], [-1e6, 3e6]])); + +var polygonFeature = new ol.Feature( + new ol.geom.Polygon([[[-3e6, -1e6], [-3e6, 1e6], + [-1e6, 1e6], [-1e6, -1e6], [-3e6, -1e6]]])); + + +var map = new ol.Map({ + interactions: ol.interaction.defaults().extend([new app.Drag()]), + layers: [ + new ol.layer.Tile({ + source: new ol.source.TileJSON({ + url: 'http://api.tiles.mapbox.com/v3/mapbox.geography-class.jsonp' + }) + }), + new ol.layer.Vector({ + source: new ol.source.Vector({ + features: [pointFeature, lineFeature, polygonFeature] + }), + style: new ol.style.Style({ + image: new ol.style.Icon(/** @type {olx.style.IconOptions} */ ({ + anchor: [0.5, 46], + anchorXUnits: 'fraction', + anchorYUnits: 'pixels', + opacity: 0.95, + src: 'data/icon.png' + })), + stroke: new ol.style.Stroke({ + width: 3, + color: [255, 0, 0, 1] + }), + fill: new ol.style.Fill({ + color: [0, 0, 255, 0.6] + }) + }) + }) + ], + target: 'map', + view: new ol.View({ + center: [0, 0], + zoom: 2 + }) +}); diff --git a/externs/olx.js b/externs/olx.js index 83c1e2f418..08168cf806 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -2430,23 +2430,64 @@ olx.interaction.PinchZoomOptions.prototype.duration; /** - * @typedef {{handleEvent: function(ol.MapBrowserEvent):boolean}} + * @typedef {{handleDownEvent: (function(ol.MapBrowserPointerEvent):boolean|undefined), + * handleDragEvent: (function(ol.MapBrowserPointerEvent)|undefined), + * handleEvent: (function(ol.MapBrowserEvent):boolean|undefined), + * handleMoveEvent: (function(ol.MapBrowserPointerEvent)|undefined), + * handleUpEvent: (function(ol.MapBrowserPointerEvent):boolean|undefined)}} * @api */ olx.interaction.PointerOptions; +/** + * Function handling "down" events. If the function returns `true` then a drag + * sequence is started. + * @type {(function(ol.MapBrowserPointerEvent):boolean|undefined)} + * @api + */ +olx.interaction.PointerOptions.prototype.handleDownEvent; + + +/** + * Function handling "drag" events. This function is called on "move" events + * during a drag sequence. + * @type {(function(ol.MapBrowserPointerEvent):boolean|undefined)} + * @api + */ +olx.interaction.PointerOptions.prototype.handleDragEvent; + + /** * Method called by the map to notify the interaction that a browser event was * dispatched to the map. The function may return `false` to prevent the * propagation of the event to other interactions in the map's interactions * chain. - * @type {function(ol.MapBrowserEvent):boolean} + * @type {(function(ol.MapBrowserEvent):boolean|undefined)} * @api */ olx.interaction.PointerOptions.prototype.handleEvent; +/** + * Function handling "move" events. This function is called on "move" events, + * also during a drag sequence (so during a drag sequence both the + * `handleDragEvent` function and this function are called). + * @type {(function(ol.MapBrowserPointerEvent):boolean|undefined)} + * @api + */ +olx.interaction.PointerOptions.prototype.handleMoveEvent; + + +/** + * Function handling "up" events. If the function returns `false` then the + * current drag sequence is stopped. + * @type {(function(ol.MapBrowserPointerEvent):boolean|undefined)} + * @api + */ +olx.interaction.PointerOptions.prototype.handleUpEvent; + + /** * @typedef {{addCondition: (ol.events.ConditionType|undefined), * condition: (ol.events.ConditionType|undefined), diff --git a/src/ol/geom/flat/transformflatgeom.js b/src/ol/geom/flat/transformflatgeom.js index 574c8bcd33..7bb08e8a83 100644 --- a/src/ol/geom/flat/transformflatgeom.js +++ b/src/ol/geom/flat/transformflatgeom.js @@ -22,7 +22,7 @@ ol.geom.flat.transform.transform2D = var m13 = goog.vec.Mat4.getElement(transform, 1, 3); var dest = goog.isDef(opt_dest) ? opt_dest : []; var i = 0; - var j, jj; + var j; for (j = offset; j < end; j += stride) { var x = flatCoordinates[j]; var y = flatCoordinates[j + 1]; @@ -34,3 +34,32 @@ ol.geom.flat.transform.transform2D = } return dest; }; + + +/** + * @param {Array.} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @param {number} deltaX Delta X. + * @param {number} deltaY Delta Y. + * @param {Array.=} opt_dest Destination. + * @return {Array.} Transformed coordinates. + */ +ol.geom.flat.transform.translate = + function(flatCoordinates, offset, end, stride, deltaX, deltaY, opt_dest) { + var dest = goog.isDef(opt_dest) ? opt_dest : []; + var i = 0; + var j, k; + for (j = offset; j < end; j += stride) { + dest[i++] = flatCoordinates[j] + deltaX; + dest[i++] = flatCoordinates[j + 1] + deltaY; + for (k = j + 2; k < j + stride; ++k) { + dest[i++] = flatCoordinates[k]; + } + } + if (goog.isDef(opt_dest) && dest.length != i) { + dest.length = i; + } + return dest; +}; diff --git a/src/ol/geom/geometry.js b/src/ol/geom/geometry.js index 90d04778d2..f2c9ebd167 100644 --- a/src/ol/geom/geometry.js +++ b/src/ol/geom/geometry.js @@ -194,6 +194,16 @@ ol.geom.Geometry.prototype.applyTransform = goog.abstractMethod; ol.geom.Geometry.prototype.intersectsExtent = goog.abstractMethod; +/** + * Translate the geometry. + * @param {number} deltaX Delta X. + * @param {number} deltaY Delta Y. + * @function + * @api + */ +ol.geom.Geometry.prototype.translate = goog.abstractMethod; + + /** * Transform each coordinate of the geometry from one coordinate reference * system to another. The geometry is modified in place. diff --git a/src/ol/geom/geometrycollection.js b/src/ol/geom/geometrycollection.js index 0ccdd1887a..ca5cb08483 100644 --- a/src/ol/geom/geometrycollection.js +++ b/src/ol/geom/geometrycollection.js @@ -277,6 +277,22 @@ ol.geom.GeometryCollection.prototype.applyTransform = function(transformFn) { }; +/** + * Translate the geometry. + * @param {number} deltaX Delta X. + * @param {number} deltaY Delta Y. + * @api + */ +ol.geom.GeometryCollection.prototype.translate = function(deltaX, deltaY) { + var geometries = this.geometries_; + var i, ii; + for (i = 0, ii = geometries.length; i < ii; ++i) { + geometries[i].translate(deltaX, deltaY); + } + this.changed(); +}; + + /** * @inheritDoc */ diff --git a/src/ol/geom/simplegeometry.js b/src/ol/geom/simplegeometry.js index 89449a1527..7ead9c8269 100644 --- a/src/ol/geom/simplegeometry.js +++ b/src/ol/geom/simplegeometry.js @@ -255,6 +255,24 @@ ol.geom.SimpleGeometry.prototype.applyTransform = function(transformFn) { }; +/** + * Translate the geometry. + * @param {number} deltaX Delta X. + * @param {number} deltaY Delta Y. + * @api + */ +ol.geom.SimpleGeometry.prototype.translate = function(deltaX, deltaY) { + var flatCoordinates = this.getFlatCoordinates(); + if (!goog.isNull(flatCoordinates)) { + var stride = this.getStride(); + ol.geom.flat.transform.translate( + flatCoordinates, 0, flatCoordinates.length, stride, + deltaX, deltaY, flatCoordinates); + this.changed(); + } +}; + + /** * @param {ol.geom.SimpleGeometry} simpleGeometry Simple geometry. * @param {goog.vec.Mat4.Number} transform Transform. diff --git a/src/ol/interaction/dragboxinteraction.js b/src/ol/interaction/dragboxinteraction.js index b64385d884..9438dca7dc 100644 --- a/src/ol/interaction/dragboxinteraction.js +++ b/src/ol/interaction/dragboxinteraction.js @@ -3,7 +3,6 @@ goog.provide('ol.DragBoxEvent'); goog.provide('ol.interaction.DragBox'); goog.require('goog.events.Event'); -goog.require('goog.functions'); goog.require('ol'); goog.require('ol.events.ConditionType'); goog.require('ol.events.condition'); @@ -86,7 +85,11 @@ goog.inherits(ol.DragBoxEvent, goog.events.Event); */ ol.interaction.DragBox = function(opt_options) { - goog.base(this); + goog.base(this, { + handleDownEvent: ol.interaction.DragBox.handleDownEvent_, + handleDragEvent: ol.interaction.DragBox.handleDragEvent_, + handleUpEvent: ol.interaction.DragBox.handleUpEvent_ + }); var options = goog.isDef(opt_options) ? opt_options : {}; @@ -120,9 +123,11 @@ goog.inherits(ol.interaction.DragBox, ol.interaction.Pointer); /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @this {ol.interaction.DragBox} + * @private */ -ol.interaction.DragBox.prototype.handlePointerDrag = function(mapBrowserEvent) { +ol.interaction.DragBox.handleDragEvent_ = function(mapBrowserEvent) { if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { return; } @@ -143,6 +148,7 @@ ol.interaction.DragBox.prototype.getGeometry = function() { /** * To be overriden by child classes. + * FIXME: use constructor option instead of relying on overridding. * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. * @protected */ @@ -150,9 +156,12 @@ ol.interaction.DragBox.prototype.onBoxEnd = goog.nullFunction; /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.DragBox} + * @private */ -ol.interaction.DragBox.prototype.handlePointerUp = function(mapBrowserEvent) { +ol.interaction.DragBox.handleUpEvent_ = function(mapBrowserEvent) { if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { return true; } @@ -173,9 +182,12 @@ ol.interaction.DragBox.prototype.handlePointerUp = function(mapBrowserEvent) { /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Start drag sequence? + * @this {ol.interaction.DragBox} + * @private */ -ol.interaction.DragBox.prototype.handlePointerDown = function(mapBrowserEvent) { +ol.interaction.DragBox.handleDownEvent_ = function(mapBrowserEvent) { if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { return false; } @@ -192,9 +204,3 @@ ol.interaction.DragBox.prototype.handlePointerDown = function(mapBrowserEvent) { return false; } }; - - -/** - * @inheritDoc - */ -ol.interaction.DragBox.prototype.shouldStopEvent = goog.functions.identity; diff --git a/src/ol/interaction/dragpaninteraction.js b/src/ol/interaction/dragpaninteraction.js index dd9c4754fa..22b207eef1 100644 --- a/src/ol/interaction/dragpaninteraction.js +++ b/src/ol/interaction/dragpaninteraction.js @@ -22,7 +22,11 @@ goog.require('ol.interaction.Pointer'); */ ol.interaction.DragPan = function(opt_options) { - goog.base(this); + goog.base(this, { + handleDownEvent: ol.interaction.DragPan.handleDownEvent_, + handleDragEvent: ol.interaction.DragPan.handleDragEvent_, + handleUpEvent: ol.interaction.DragPan.handleUpEvent_ + }); var options = goog.isDef(opt_options) ? opt_options : {}; @@ -61,9 +65,11 @@ goog.inherits(ol.interaction.DragPan, ol.interaction.Pointer); /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @this {ol.interaction.DragPan} + * @private */ -ol.interaction.DragPan.prototype.handlePointerDrag = function(mapBrowserEvent) { +ol.interaction.DragPan.handleDragEvent_ = function(mapBrowserEvent) { goog.asserts.assert(this.targetPointers.length >= 1); var centroid = ol.interaction.Pointer.centroid(this.targetPointers); @@ -89,9 +95,12 @@ ol.interaction.DragPan.prototype.handlePointerDrag = function(mapBrowserEvent) { /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.DragPan} + * @private */ -ol.interaction.DragPan.prototype.handlePointerUp = function(mapBrowserEvent) { +ol.interaction.DragPan.handleUpEvent_ = function(mapBrowserEvent) { var map = mapBrowserEvent.map; var view = map.getView(); if (this.targetPointers.length === 0) { @@ -121,9 +130,12 @@ ol.interaction.DragPan.prototype.handlePointerUp = function(mapBrowserEvent) { /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Start drag sequence? + * @this {ol.interaction.DragPan} + * @private */ -ol.interaction.DragPan.prototype.handlePointerDown = function(mapBrowserEvent) { +ol.interaction.DragPan.handleDownEvent_ = function(mapBrowserEvent) { if (this.targetPointers.length > 0 && this.condition_(mapBrowserEvent)) { var map = mapBrowserEvent.map; var view = map.getView(); @@ -148,3 +160,9 @@ ol.interaction.DragPan.prototype.handlePointerDown = function(mapBrowserEvent) { return false; } }; + + +/** + * @inheritDoc + */ +ol.interaction.DragPan.prototype.shouldStopEvent = goog.functions.FALSE; diff --git a/src/ol/interaction/dragrotateandzoominteraction.js b/src/ol/interaction/dragrotateandzoominteraction.js index 8a45302a9d..a39d5e0094 100644 --- a/src/ol/interaction/dragrotateandzoominteraction.js +++ b/src/ol/interaction/dragrotateandzoominteraction.js @@ -1,7 +1,6 @@ goog.provide('ol.interaction.DragRotateAndZoom'); goog.require('goog.asserts'); -goog.require('goog.functions'); goog.require('goog.math.Vec2'); goog.require('ol'); goog.require('ol.ViewHint'); @@ -31,7 +30,11 @@ ol.interaction.DragRotateAndZoom = function(opt_options) { var options = goog.isDef(opt_options) ? opt_options : {}; - goog.base(this); + goog.base(this, { + handleDownEvent: ol.interaction.DragRotateAndZoom.handleDownEvent_, + handleDragEvent: ol.interaction.DragRotateAndZoom.handleDragEvent_, + handleUpEvent: ol.interaction.DragRotateAndZoom.handleUpEvent_ + }); /** * @private @@ -64,10 +67,11 @@ goog.inherits(ol.interaction.DragRotateAndZoom, /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @this {ol.interaction.DragRotateAndZoom} + * @private */ -ol.interaction.DragRotateAndZoom.prototype.handlePointerDrag = - function(mapBrowserEvent) { +ol.interaction.DragRotateAndZoom.handleDragEvent_ = function(mapBrowserEvent) { if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { return; } @@ -101,10 +105,12 @@ ol.interaction.DragRotateAndZoom.prototype.handlePointerDrag = /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.DragRotateAndZoom} + * @private */ -ol.interaction.DragRotateAndZoom.prototype.handlePointerUp = - function(mapBrowserEvent) { +ol.interaction.DragRotateAndZoom.handleUpEvent_ = function(mapBrowserEvent) { if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { return true; } @@ -124,10 +130,12 @@ ol.interaction.DragRotateAndZoom.prototype.handlePointerUp = /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Start drag sequence? + * @this {ol.interaction.DragRotateAndZoom} + * @private */ -ol.interaction.DragRotateAndZoom.prototype.handlePointerDown = - function(mapBrowserEvent) { +ol.interaction.DragRotateAndZoom.handleDownEvent_ = function(mapBrowserEvent) { if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { return false; } @@ -141,12 +149,3 @@ ol.interaction.DragRotateAndZoom.prototype.handlePointerDown = return false; } }; - - -/** - * @inheritDoc - * Stop the event if it was handled, so that interaction `DragZoom` - * does not interfere. - */ -ol.interaction.DragRotateAndZoom.prototype.shouldStopEvent = - goog.functions.identity; diff --git a/src/ol/interaction/dragrotateinteraction.js b/src/ol/interaction/dragrotateinteraction.js index 8ed93ce0a9..d7e3a73884 100644 --- a/src/ol/interaction/dragrotateinteraction.js +++ b/src/ol/interaction/dragrotateinteraction.js @@ -27,7 +27,11 @@ ol.interaction.DragRotate = function(opt_options) { var options = goog.isDef(opt_options) ? opt_options : {}; - goog.base(this); + goog.base(this, { + handleDownEvent: ol.interaction.DragRotate.handleDownEvent_, + handleDragEvent: ol.interaction.DragRotate.handleDragEvent_, + handleUpEvent: ol.interaction.DragRotate.handleUpEvent_ + }); /** * @private @@ -47,10 +51,11 @@ goog.inherits(ol.interaction.DragRotate, ol.interaction.Pointer); /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @this {ol.interaction.DragRotate} + * @private */ -ol.interaction.DragRotate.prototype.handlePointerDrag = - function(mapBrowserEvent) { +ol.interaction.DragRotate.handleDragEvent_ = function(mapBrowserEvent) { if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { return; } @@ -73,10 +78,12 @@ ol.interaction.DragRotate.prototype.handlePointerDrag = /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.DragRotate} + * @private */ -ol.interaction.DragRotate.prototype.handlePointerUp = - function(mapBrowserEvent) { +ol.interaction.DragRotate.handleUpEvent_ = function(mapBrowserEvent) { if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { return true; } @@ -92,10 +99,12 @@ ol.interaction.DragRotate.prototype.handlePointerUp = /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Start drag sequence? + * @this {ol.interaction.DragRotate} + * @private */ -ol.interaction.DragRotate.prototype.handlePointerDown = - function(mapBrowserEvent) { +ol.interaction.DragRotate.handleDownEvent_ = function(mapBrowserEvent) { if (!ol.events.condition.mouseOnly(mapBrowserEvent)) { return false; } @@ -111,3 +120,9 @@ ol.interaction.DragRotate.prototype.handlePointerDown = return false; } }; + + +/** + * @inheritDoc + */ +ol.interaction.DragRotate.prototype.shouldStopEvent = goog.functions.FALSE; diff --git a/src/ol/interaction/drawinteraction.js b/src/ol/interaction/drawinteraction.js index 94354c66bc..352985e781 100644 --- a/src/ol/interaction/drawinteraction.js +++ b/src/ol/interaction/drawinteraction.js @@ -86,7 +86,9 @@ goog.inherits(ol.DrawEvent, goog.events.Event); ol.interaction.Draw = function(options) { goog.base(this, { - handleEvent: ol.interaction.Draw.handleEvent + handleDownEvent: ol.interaction.Draw.handleDownEvent_, + handleEvent: ol.interaction.Draw.handleEvent, + handleUpEvent: ol.interaction.Draw.handleUpEvent_ }); /** @@ -259,11 +261,12 @@ ol.interaction.Draw.handleEvent = function(mapBrowserEvent) { /** - * Handle down events. - * @param {ol.MapBrowserEvent} event A down event. - * @return {boolean} Pass the event to other interactions. + * @param {ol.MapBrowserPointerEvent} event Event. + * @return {boolean} Start drag sequence? + * @this {ol.interaction.Draw} + * @private */ -ol.interaction.Draw.prototype.handlePointerDown = function(event) { +ol.interaction.Draw.handleDownEvent_ = function(event) { if (this.condition_(event)) { this.downPx_ = event.pixel; return true; @@ -274,11 +277,12 @@ ol.interaction.Draw.prototype.handlePointerDown = function(event) { /** - * Handle up events. - * @param {ol.MapBrowserEvent} event An up event. - * @return {boolean} Pass the event to other interactions. + * @param {ol.MapBrowserPointerEvent} event Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.Draw} + * @private */ -ol.interaction.Draw.prototype.handlePointerUp = function(event) { +ol.interaction.Draw.handleUpEvent_ = function(event) { var downPx = this.downPx_; var clickPx = event.pixel; var dx = downPx[0] - clickPx[0]; @@ -550,6 +554,12 @@ ol.interaction.Draw.prototype.abortDrawing_ = function() { }; +/** + * @inheritDoc + */ +ol.interaction.Draw.prototype.shouldStopEvent = goog.functions.FALSE; + + /** * Redraw the skecth features. * @private diff --git a/src/ol/interaction/modifyinteraction.js b/src/ol/interaction/modifyinteraction.js index 147d668840..8446a7b6ca 100644 --- a/src/ol/interaction/modifyinteraction.js +++ b/src/ol/interaction/modifyinteraction.js @@ -48,7 +48,10 @@ ol.interaction.SegmentDataType; ol.interaction.Modify = function(options) { goog.base(this, { - handleEvent: ol.interaction.Modify.handleEvent + handleDownEvent: ol.interaction.Modify.handleDownEvent_, + handleDragEvent: ol.interaction.Modify.handleDragEvent_, + handleEvent: ol.interaction.Modify.handleEvent, + handleUpEvent: ol.interaction.Modify.handleUpEvent_ }); /** @@ -389,9 +392,12 @@ ol.interaction.Modify.prototype.createOrUpdateVertexFeature_ = /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} evt Event. + * @return {boolean} Start drag sequence? + * @this {ol.interaction.Modify} + * @private */ -ol.interaction.Modify.prototype.handlePointerDown = function(evt) { +ol.interaction.Modify.handleDownEvent_ = function(evt) { this.handlePointerAtPixel_(evt.pixel, evt.map); this.dragSegments_ = []; var vertexFeature = this.vertexFeature_; @@ -421,9 +427,11 @@ ol.interaction.Modify.prototype.handlePointerDown = function(evt) { /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} evt Event. + * @this {ol.interaction.Modify} + * @private */ -ol.interaction.Modify.prototype.handlePointerDrag = function(evt) { +ol.interaction.Modify.handleDragEvent_ = function(evt) { var vertex = evt.coordinate; for (var i = 0, ii = this.dragSegments_.length; i < ii; ++i) { var dragSegment = this.dragSegments_[i]; @@ -472,9 +480,12 @@ ol.interaction.Modify.prototype.handlePointerDrag = function(evt) { /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} evt Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.Modify} + * @private */ -ol.interaction.Modify.prototype.handlePointerUp = function(evt) { +ol.interaction.Modify.handleUpEvent_ = function(evt) { var segmentData; for (var i = this.dragSegments_.length - 1; i >= 0; --i) { segmentData = this.dragSegments_[i][0]; @@ -749,12 +760,6 @@ ol.interaction.Modify.prototype.removeVertex_ = function() { }; -/** - * @inheritDoc - */ -ol.interaction.Modify.prototype.shouldStopEvent = goog.functions.identity; - - /** * @param {ol.geom.SimpleGeometry} geometry Geometry. * @param {number} index Index. diff --git a/src/ol/interaction/pinchrotateinteraction.js b/src/ol/interaction/pinchrotateinteraction.js index 8d23886ada..e1aa2fc806 100644 --- a/src/ol/interaction/pinchrotateinteraction.js +++ b/src/ol/interaction/pinchrotateinteraction.js @@ -22,7 +22,11 @@ goog.require('ol.interaction.Pointer'); */ ol.interaction.PinchRotate = function(opt_options) { - goog.base(this); + goog.base(this, { + handleDownEvent: ol.interaction.PinchRotate.handleDownEvent_, + handleDragEvent: ol.interaction.PinchRotate.handleDragEvent_, + handleUpEvent: ol.interaction.PinchRotate.handleUpEvent_ + }); var options = goog.isDef(opt_options) ? opt_options : {}; @@ -61,10 +65,11 @@ goog.inherits(ol.interaction.PinchRotate, ol.interaction.Pointer); /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @this {ol.interaction.PinchRotate} + * @private */ -ol.interaction.PinchRotate.prototype.handlePointerDrag = - function(mapBrowserEvent) { +ol.interaction.PinchRotate.handleDragEvent_ = function(mapBrowserEvent) { goog.asserts.assert(this.targetPointers.length >= 2); var rotationDelta = 0.0; @@ -111,10 +116,12 @@ ol.interaction.PinchRotate.prototype.handlePointerDrag = /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.PinchRotate} + * @private */ -ol.interaction.PinchRotate.prototype.handlePointerUp = - function(mapBrowserEvent) { +ol.interaction.PinchRotate.handleUpEvent_ = function(mapBrowserEvent) { if (this.targetPointers.length < 2) { var map = mapBrowserEvent.map; var view = map.getView(); @@ -133,10 +140,12 @@ ol.interaction.PinchRotate.prototype.handlePointerUp = /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Start drag sequence? + * @this {ol.interaction.PinchRotate} + * @private */ -ol.interaction.PinchRotate.prototype.handlePointerDown = - function(mapBrowserEvent) { +ol.interaction.PinchRotate.handleDownEvent_ = function(mapBrowserEvent) { if (this.targetPointers.length >= 2) { var map = mapBrowserEvent.map; this.anchor_ = null; @@ -152,3 +161,9 @@ ol.interaction.PinchRotate.prototype.handlePointerDown = return false; } }; + + +/** + * @inheritDoc + */ +ol.interaction.PinchRotate.prototype.shouldStopEvent = goog.functions.FALSE; diff --git a/src/ol/interaction/pinchzoominteraction.js b/src/ol/interaction/pinchzoominteraction.js index 61d0f076e9..dbe9fff841 100644 --- a/src/ol/interaction/pinchzoominteraction.js +++ b/src/ol/interaction/pinchzoominteraction.js @@ -21,9 +21,13 @@ goog.require('ol.interaction.Pointer'); */ ol.interaction.PinchZoom = function(opt_options) { - var options = goog.isDef(opt_options) ? opt_options : {}; + goog.base(this, { + handleDownEvent: ol.interaction.PinchZoom.handleDownEvent_, + handleDragEvent: ol.interaction.PinchZoom.handleDragEvent_, + handleUpEvent: ol.interaction.PinchZoom.handleUpEvent_ + }); - goog.base(this); + var options = goog.isDef(opt_options) ? opt_options : {}; /** * @private @@ -54,10 +58,11 @@ goog.inherits(ol.interaction.PinchZoom, ol.interaction.Pointer); /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @this {ol.interaction.PinchZoom} + * @private */ -ol.interaction.PinchZoom.prototype.handlePointerDrag = - function(mapBrowserEvent) { +ol.interaction.PinchZoom.handleDragEvent_ = function(mapBrowserEvent) { goog.asserts.assert(this.targetPointers.length >= 2); var scaleDelta = 1.0; @@ -98,9 +103,12 @@ ol.interaction.PinchZoom.prototype.handlePointerDrag = /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Stop drag sequence? + * @this {ol.interaction.PinchZoom} + * @private */ -ol.interaction.PinchZoom.prototype.handlePointerUp = +ol.interaction.PinchZoom.handleUpEvent_ = function(mapBrowserEvent) { if (this.targetPointers.length < 2) { var map = mapBrowserEvent.map; @@ -121,9 +129,12 @@ ol.interaction.PinchZoom.prototype.handlePointerUp = /** - * @inheritDoc + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @return {boolean} Start drag sequence? + * @this {ol.interaction.PinchZoom} + * @private */ -ol.interaction.PinchZoom.prototype.handlePointerDown = +ol.interaction.PinchZoom.handleDownEvent_ = function(mapBrowserEvent) { if (this.targetPointers.length >= 2) { var map = mapBrowserEvent.map; @@ -139,3 +150,9 @@ ol.interaction.PinchZoom.prototype.handlePointerDown = return false; } }; + + +/** + * @inheritDoc + */ +ol.interaction.PinchZoom.prototype.shouldStopEvent = goog.functions.FALSE; diff --git a/src/ol/interaction/pointerinteraction.js b/src/ol/interaction/pointerinteraction.js index 8b90261450..ba730b2807 100644 --- a/src/ol/interaction/pointerinteraction.js +++ b/src/ol/interaction/pointerinteraction.js @@ -3,7 +3,6 @@ goog.provide('ol.interaction.Pointer'); goog.require('goog.asserts'); goog.require('goog.functions'); goog.require('goog.object'); -goog.require('ol.MapBrowserEvent'); goog.require('ol.MapBrowserEvent.EventType'); goog.require('ol.MapBrowserPointerEvent'); goog.require('ol.Pixel'); @@ -13,8 +12,13 @@ goog.require('ol.interaction.Interaction'); /** * @classdesc - * Abstract base class; normally only used for creating subclasses and not - * instantiated in apps. + * Base class that calls user-defined functions on `down`, `move` and `up` + * events. This class also manages "drag sequences". + * + * When the `handleDownEvent` user function returns `true` a drag sequence is + * started. During a drag sequence the `handleDragEvent` user function is + * called on `move` events. The drag sequence ends when the `handleUpEvent` + * user function is called and returns `false`. * * @constructor * @param {olx.interaction.PointerOptions=} opt_options Options. @@ -32,6 +36,34 @@ ol.interaction.Pointer = function(opt_options) { handleEvent: handleEvent }); + /** + * @type {function(ol.MapBrowserPointerEvent):boolean} + * @private + */ + this.handleDownEvent_ = goog.isDef(options.handleDownEvent) ? + options.handleDownEvent : ol.interaction.Pointer.handleDownEvent; + + /** + * @type {function(ol.MapBrowserPointerEvent)} + * @private + */ + this.handleDragEvent_ = goog.isDef(options.handleDragEvent) ? + options.handleDragEvent : ol.interaction.Pointer.handleDragEvent; + + /** + * @type {function(ol.MapBrowserPointerEvent)} + * @private + */ + this.handleMoveEvent_ = goog.isDef(options.handleMoveEvent) ? + options.handleMoveEvent : ol.interaction.Pointer.handleMoveEvent; + + /** + * @type {function(ol.MapBrowserPointerEvent):boolean} + * @private + */ + this.handleUpEvent_ = goog.isDef(options.handleUpEvent) ? + options.handleUpEvent : ol.interaction.Pointer.handleUpEvent; + /** * @type {boolean} * @protected @@ -111,25 +143,32 @@ ol.interaction.Pointer.prototype.updateTrackedPointers_ = /** * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @protected + * @this {ol.interaction.Pointer} */ -ol.interaction.Pointer.prototype.handlePointerDrag = goog.nullFunction; +ol.interaction.Pointer.handleDragEvent = goog.nullFunction; /** * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @protected * @return {boolean} Capture dragging. + * @this {ol.interaction.Pointer} */ -ol.interaction.Pointer.prototype.handlePointerUp = goog.functions.FALSE; +ol.interaction.Pointer.handleUpEvent = goog.functions.FALSE; /** * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. - * @protected * @return {boolean} Capture dragging. + * @this {ol.interaction.Pointer} */ -ol.interaction.Pointer.prototype.handlePointerDown = goog.functions.FALSE; +ol.interaction.Pointer.handleDownEvent = goog.functions.FALSE; + + +/** + * @param {ol.MapBrowserPointerEvent} mapBrowserEvent Event. + * @this {ol.interaction.Pointer} + */ +ol.interaction.Pointer.handleMoveEvent = goog.nullFunction; /** @@ -148,29 +187,35 @@ ol.interaction.Pointer.handleEvent = function(mapBrowserEvent) { if (this.handlingDownUpSequence) { if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERDRAG) { - this.handlePointerDrag(mapBrowserEvent); + this.handleDragEvent_(mapBrowserEvent); } else if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERUP) { this.handlingDownUpSequence = - this.handlePointerUp(mapBrowserEvent); + this.handleUpEvent_(mapBrowserEvent); } } if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERDOWN) { - var handled = this.handlePointerDown(mapBrowserEvent); + var handled = this.handleDownEvent_(mapBrowserEvent); this.handlingDownUpSequence = handled; stopEvent = this.shouldStopEvent(handled); + } else if (mapBrowserEvent.type == ol.MapBrowserEvent.EventType.POINTERMOVE) { + this.handleMoveEvent_(mapBrowserEvent); } return !stopEvent; }; /** - * This method allows inheriting classes to stop the event from being - * passed to further interactions. For example, this is required for - * interaction `DragRotateAndZoom`. + * This method is used to determine if "down" events should be propagated to + * other interactions or should be stopped. + * + * The method receives the return code of the "handleDownEvent" function. + * + * By default this function is the "identity" function. It's overidden in + * child classes. * - * @protected * @param {boolean} handled Was the event handled by the interaction? * @return {boolean} Should the event be stopped? + * @protected */ -ol.interaction.Pointer.prototype.shouldStopEvent = goog.functions.FALSE; +ol.interaction.Pointer.prototype.shouldStopEvent = goog.functions.identity; diff --git a/src/ol/map.js b/src/ol/map.js index ba42b80d8b..19d25f7e94 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -645,6 +645,19 @@ goog.exportProperty( ol.Map.prototype.getTarget); +/** + * Get the DOM element into which this map is rendered. In contrast to + * `getTarget` this method always return an `Element`, or `null` if the + * map has no target. + * @return {Element} The element that the map is rendered in. + * @api + */ +ol.Map.prototype.getTargetElement = function() { + var target = this.getTarget(); + return goog.isDef(target) ? goog.dom.getElement(target) : null; +}; + + /** * @param {ol.Pixel} pixel Pixel. * @return {ol.Coordinate} Coordinate. diff --git a/test/spec/ol/geom/flat/transformflatgeom.js b/test/spec/ol/geom/flat/transformflatgeom.test.js similarity index 83% rename from test/spec/ol/geom/flat/transformflatgeom.js rename to test/spec/ol/geom/flat/transformflatgeom.test.js index dd3689bd52..c661116a88 100644 --- a/test/spec/ol/geom/flat/transformflatgeom.js +++ b/test/spec/ol/geom/flat/transformflatgeom.test.js @@ -62,6 +62,22 @@ describe('ol.geom.flat.transform', function() { }); + describe('ol.geom.flat.transform.translate', function() { + it('translates the coordinates array', function() { + var multiPolygon = new ol.geom.MultiPolygon([ + [[[0, 0, 2], [0, 1, 2], [1, 1, 2], [1, 0, 2], [0, 0, 2]]], + [[[2, 2, 3], [2, 3, 3], [3, 3, 3], [3, 2, 3], [2, 2, 3]]]]); + var flatCoordinates = multiPolygon.getFlatCoordinates(); + var deltaX = 1; + var deltaY = 2; + ol.geom.flat.transform.translate(flatCoordinates, 0, + flatCoordinates.length, multiPolygon.getStride(), + deltaX, deltaY, flatCoordinates); + expect(flatCoordinates).to.eql([ + 1, 2, 2, 1, 3, 2, 2, 3, 2, 2, 2, 2, 1, 2, 2, + 3, 4, 3, 3, 5, 3, 4, 5, 3, 4, 4, 3, 3, 4, 3]); + }); + }); });