From 6cb02724da0189d39013fd68bebf5cfd9dccdd8d Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Wed, 22 Jan 2014 16:46:26 +0100 Subject: [PATCH 1/3] Make ol.interaction.DragAndDrop fire an event instead of managing layers and sources --- src/objectliterals.jsdoc | 11 +- .../draganddropinteraction.exports | 3 + src/ol/interaction/draganddropinteraction.js | 126 ++++++++++-------- 3 files changed, 75 insertions(+), 65 deletions(-) diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index 6124101b82..6c1c23e5f1 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -282,17 +282,10 @@ /** * @typedef {Object} olx.interaction.DragAndDropOptions - * @property {boolean|undefined} fitView Fit view. Default is `true`. * @property {Array.|undefined} formatConstructors * Format constructors. - * @property {ol.source.Vector|undefined} source Source. If this is defined - * then features will be added to this source. - * @property {ol.layer.Vector|undefined} layer Layer. If this is defined then - * features will be added to this layer's source. If neither `source` nor - * `layer` are defined then the dropped features will be added as a new - * layer. - * @property {ol.feature.StyleFunction|undefined} styleFunction Style function. - * This is used to configure any new layers created. + * @property {ol.proj.ProjectionLike} reprojectTo Target projection. By + * default, the map's view's projection is used. */ /** diff --git a/src/ol/interaction/draganddropinteraction.exports b/src/ol/interaction/draganddropinteraction.exports index 50e9fef9e3..0e8bc5ea27 100644 --- a/src/ol/interaction/draganddropinteraction.exports +++ b/src/ol/interaction/draganddropinteraction.exports @@ -1 +1,4 @@ @exportSymbol ol.interaction.DragAndDrop + +@exportProperty ol.interaction.DragAndDropEvent.prototype.getFeatures +@exportProperty ol.interaction.DragAndDropEvent.prototype.getProjection diff --git a/src/ol/interaction/draganddropinteraction.js b/src/ol/interaction/draganddropinteraction.js index 329a3c5172..c9cf155fee 100644 --- a/src/ol/interaction/draganddropinteraction.js +++ b/src/ol/interaction/draganddropinteraction.js @@ -1,18 +1,18 @@ // FIXME should handle all geo-referenced data, not just vector data goog.provide('ol.interaction.DragAndDrop'); +goog.provide('ol.interaction.DragAndDropEvent'); goog.require('goog.array'); goog.require('goog.asserts'); goog.require('goog.events'); +goog.require('goog.events.Event'); goog.require('goog.events.FileDropHandler'); goog.require('goog.events.FileDropHandler.EventType'); goog.require('goog.fs.FileReader'); goog.require('goog.functions'); goog.require('ol.interaction.Interaction'); -goog.require('ol.layer.Vector'); goog.require('ol.proj'); -goog.require('ol.source.Vector'); @@ -27,12 +27,6 @@ ol.interaction.DragAndDrop = function(opt_options) { goog.base(this); - /** - * @private - * @type {boolean} - */ - this.fitView_ = goog.isDef(options.fitView) ? options.fitView : true; - /** * @private * @type {Array.} @@ -42,21 +36,10 @@ ol.interaction.DragAndDrop = function(opt_options) { /** * @private - * @type {ol.source.Vector} + * @type {ol.proj.Projection} */ - this.source_ = goog.isDef(options.source) ? options.source : null; - - /** - * @private - * @type {ol.layer.Vector} - */ - this.layer_ = goog.isDef(options.layer) ? options.layer : null; - - /** - * @private - * @type {ol.feature.StyleFunction|undefined} - */ - this.styleFunction_ = options.styleFunction; + this.reprojectTo_ = goog.isDef(options.reprojectTo) ? + ol.proj.get(options.reprojectTo) : null; /** * @private @@ -108,16 +91,12 @@ ol.interaction.DragAndDrop.prototype.handleDrop_ = function(event) { ol.interaction.DragAndDrop.prototype.handleResult_ = function(result) { var map = this.getMap(); goog.asserts.assert(!goog.isNull(map)); - var view = map.getView(); - goog.asserts.assert(goog.isDef(view)); - var view2D = view.getView2D(); - var targetProjection; - if (!goog.isNull(this.source_)) { - targetProjection = this.source_.getProjection(); - } else if (!goog.isNull(this.layer_)) { - targetProjection = this.layer_.getSource().getProjection(); - } else { - targetProjection = view2D.getProjection(); + var projection = this.reprojectTo_; + if (goog.isNull(projection)) { + var view = map.getView(); + goog.asserts.assert(goog.isDef(view)); + projection = view.getView2D().getProjection(); + goog.asserts.assert(goog.isDef(projection)); } var formatConstructors = this.formatConstructors_; var features = []; @@ -128,7 +107,7 @@ ol.interaction.DragAndDrop.prototype.handleResult_ = function(result) { var readFeatures = this.tryReadFeatures_(format, result); if (!goog.isNull(readFeatures)) { var featureProjection = format.readProjection(result); - var transform = ol.proj.getTransform(featureProjection, targetProjection); + var transform = ol.proj.getTransform(featureProjection, projection); var j, jj; for (j = 0, jj = readFeatures.length; j < jj; ++j) { var feature = readFeatures[j]; @@ -140,29 +119,10 @@ ol.interaction.DragAndDrop.prototype.handleResult_ = function(result) { } } } - if (features.length > 0) { - var source; - if (!goog.isNull(this.source_)) { - source = this.source_; - } else if (!goog.isNull(this.layer_)) { - source = this.layer_.getSource(); - goog.asserts.assertInstanceof(source, ol.source.Vector); - } else { - source = new ol.source.Vector(); - } - for (i = 0, ii = features.length; i < ii; ++i) { - source.addFeature(features[i]); - } - if (goog.isNull(this.layer_)) { - map.getLayers().push(new ol.layer.Vector({ - styleFunction: this.styleFunction_, - source: source - })); - } - if (this.fitView_) { - view2D.fitExtent(source.getExtent(), map.getSize()); - } - } + this.dispatchEvent( + new ol.interaction.DragAndDropEvent( + ol.interaction.DragAndDropEventType.ADD_FEATURES, this, features, + projection)); }; @@ -209,3 +169,57 @@ ol.interaction.DragAndDrop.prototype.tryReadFeatures_ = function(format, text) { return null; } }; + + +/** + * @enum {string} + */ +ol.interaction.DragAndDropEventType = { + ADD_FEATURES: 'addfeatures' +}; + + + +/** + * @constructor + * @extends {goog.events.Event} + * @param {ol.interaction.DragAndDropEventType} type Type. + * @param {Object=} opt_target Target. + * @param {Array.=} opt_features Features. + * @param {ol.proj.Projection=} opt_projection Projection. + */ +ol.interaction.DragAndDropEvent = + function(type, opt_target, opt_features, opt_projection) { + + goog.base(this, type, opt_target); + + /** + * @private + * @type {Array.|undefined} + */ + this.features_ = opt_features; + + /** + * @private + * @type {ol.proj.Projection|undefined} + */ + this.projection_ = opt_projection; + +}; +goog.inherits(ol.interaction.DragAndDropEvent, goog.events.Event); + + +/** + * @return {Array.|undefined} Features. + */ +ol.interaction.DragAndDropEvent.prototype.getFeatures = function() { + return this.features_; +}; + + +/** + * @return {ol.proj.Projection|undefined} Projection. + */ +ol.interaction.DragAndDropEvent.prototype.getProjection = function() { + return this.projection_; +}; From b2dc09765089da4ae62b2ff3ea23a919698e0668 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Wed, 22 Jan 2014 16:47:03 +0100 Subject: [PATCH 2/3] Use ol.interaction.DragAndDrop addfeatures event in drag-and-drop example --- examples/drag-and-drop.js | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/examples/drag-and-drop.js b/examples/drag-and-drop.js index ce8d40780d..2c05bcee5d 100644 --- a/examples/drag-and-drop.js +++ b/examples/drag-and-drop.js @@ -9,7 +9,9 @@ goog.require('ol.format.TopoJSON'); goog.require('ol.interaction'); goog.require('ol.interaction.DragAndDrop'); goog.require('ol.layer.Tile'); +goog.require('ol.layer.Vector'); goog.require('ol.source.BingMaps'); +goog.require('ol.source.Vector'); goog.require('ol.style.Circle'); goog.require('ol.style.Fill'); goog.require('ol.style.Stroke'); @@ -82,19 +84,18 @@ var styleFunction = function(feature, resolution) { } }; +var dragAndDropInteraction = new ol.interaction.DragAndDrop({ + formatConstructors: [ + ol.format.GPX, + ol.format.GeoJSON, + ol.format.IGC, + ol.format.KML, + ol.format.TopoJSON + ] +}); + var map = new ol.Map({ - interactions: ol.interaction.defaults().extend([ - new ol.interaction.DragAndDrop({ - formatConstructors: [ - ol.format.GPX, - ol.format.GeoJSON, - ol.format.IGC, - ol.format.KML, - ol.format.TopoJSON - ], - styleFunction: styleFunction - }) - ]), + interactions: ol.interaction.defaults().extend([dragAndDropInteraction]), layers: [ new ol.layer.Tile({ source: new ol.source.BingMaps({ @@ -111,6 +112,19 @@ var map = new ol.Map({ }) }); +dragAndDropInteraction.on('addfeatures', function(event) { + var vectorSource = new ol.source.Vector({ + features: event.getFeatures(), + projection: event.getProjection() + }); + map.getLayers().push(new ol.layer.Vector({ + source: vectorSource, + styleFunction: styleFunction + })); + var view2D = map.getView().getView2D(); + view2D.fitExtent(vectorSource.getExtent(), map.getSize()); +}); + var displayFeatureInfo = function(pixel) { var features = []; map.forEachFeatureAtPixel(pixel, function(feature, layer) { From e77a5b61d5c2e5863b82af564d599656913fa2d9 Mon Sep 17 00:00:00 2001 From: Tom Payne Date: Wed, 22 Jan 2014 16:47:33 +0100 Subject: [PATCH 3/3] Add drag-and-drop-image-vector example --- examples/drag-and-drop-image-vector.html | 55 ++++++++ examples/drag-and-drop-image-vector.js | 156 +++++++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 examples/drag-and-drop-image-vector.html create mode 100644 examples/drag-and-drop-image-vector.js diff --git a/examples/drag-and-drop-image-vector.html b/examples/drag-and-drop-image-vector.html new file mode 100644 index 0000000000..e19c422047 --- /dev/null +++ b/examples/drag-and-drop-image-vector.html @@ -0,0 +1,55 @@ + + + + + + + + + + Drag-and-Drop image vector example + + + + + +
+ +
+
+
+
+
+ +
+ +
+

Drag-and-Drop image vector example

+

Example of using the drag-and-drop interaction with a ol.source.ImageVector. Drag and drop GPX, GeoJSON, IGC, KML, or TopoJSON files on to the map. Each file is rendered to an image on the client.

+
+

See the drag-and-drop-image-vector.js source to see how this is done.

+
+
drag-and-drop-image-vector, gpx, geojson, igc, kml, topojson, vector, image
+
+
+
+   +
+
+ +
+ +
+ + + + + + + diff --git a/examples/drag-and-drop-image-vector.js b/examples/drag-and-drop-image-vector.js new file mode 100644 index 0000000000..9a6886af52 --- /dev/null +++ b/examples/drag-and-drop-image-vector.js @@ -0,0 +1,156 @@ +goog.require('ol.Map'); +goog.require('ol.RendererHints'); +goog.require('ol.View2D'); +goog.require('ol.format.GPX'); +goog.require('ol.format.GeoJSON'); +goog.require('ol.format.IGC'); +goog.require('ol.format.KML'); +goog.require('ol.format.TopoJSON'); +goog.require('ol.interaction'); +goog.require('ol.interaction.DragAndDrop'); +goog.require('ol.layer.Image'); +goog.require('ol.layer.Tile'); +goog.require('ol.source.BingMaps'); +goog.require('ol.source.ImageVector'); +goog.require('ol.source.Vector'); +goog.require('ol.style.Circle'); +goog.require('ol.style.Fill'); +goog.require('ol.style.Stroke'); +goog.require('ol.style.Style'); + + +var defaultStyle = { + 'Point': [new ol.style.Style({ + image: new ol.style.Circle({ + fill: new ol.style.Fill({ + color: 'rgba(255,255,0,0.5)' + }), + radius: 5, + stroke: new ol.style.Stroke({ + color: '#ff0', + width: 1 + }) + }) + })], + 'LineString': [new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: '#f00', + width: 3 + }) + })], + 'Polygon': [new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(0,255,255,0.5)' + }), + stroke: new ol.style.Stroke({ + color: '#0ff', + width: 1 + }) + })], + 'MultiPoint': [new ol.style.Style({ + image: new ol.style.Circle({ + fill: new ol.style.Fill({ + color: 'rgba(255,0,255,0.5)' + }), + radius: 5, + stroke: new ol.style.Stroke({ + color: '#f0f', + width: 1 + }) + }) + })], + 'MultiLineString': [new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: '#0f0', + width: 3 + }) + })], + 'MultiPolygon': [new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(0,0,255,0.5)' + }), + stroke: new ol.style.Stroke({ + color: '#00f', + width: 1 + }) + })] +}; + +var styleFunction = function(feature, resolution) { + var featureStyleFunction = feature.getStyleFunction(); + if (featureStyleFunction) { + return featureStyleFunction.call(feature, resolution); + } else { + return defaultStyle[feature.getGeometry().getType()]; + } +}; + +var dragAndDropInteraction = new ol.interaction.DragAndDrop({ + formatConstructors: [ + ol.format.GPX, + ol.format.GeoJSON, + ol.format.IGC, + ol.format.KML, + ol.format.TopoJSON + ] +}); + +var map = new ol.Map({ + interactions: ol.interaction.defaults().extend([dragAndDropInteraction]), + layers: [ + new ol.layer.Tile({ + source: new ol.source.BingMaps({ + imagerySet: 'Aerial', + key: 'Ak-dzM4wZjSqTlzveKz5u0d4IQ4bRzVI309GxmkgSVr1ewS6iPSrOvOKhA-CJlm3' + }) + }) + ], + renderers: ol.RendererHints.createFromQueryData(), + target: 'map', + view: new ol.View2D({ + center: [0, 0], + zoom: 2 + }) +}); + +dragAndDropInteraction.on('addfeatures', function(event) { + var vectorSource = new ol.source.Vector({ + features: event.getFeatures(), + projection: event.getProjection() + }); + map.getLayers().push(new ol.layer.Image({ + source: new ol.source.ImageVector({ + source: vectorSource, + styleFunction: styleFunction + }) + })); + var view2D = map.getView().getView2D(); + view2D.fitExtent(vectorSource.getExtent(), map.getSize()); +}); + +var displayFeatureInfo = function(pixel) { + var features = []; + map.forEachFeatureAtPixel(pixel, function(feature, layer) { + features.push(feature); + }); + if (features.length > 0) { + var info = []; + var i, ii; + for (i = 0, ii = features.length; i < ii; ++i) { + info.push(features[i].get('name')); + } + document.getElementById('info').innerHTML = info.join(', ') || ' '; + } else { + document.getElementById('info').innerHTML = ' '; + } +}; + +$(map.getViewport()).on('mousemove', function(evt) { + var pixel = map.getEventPixel(evt.originalEvent); + displayFeatureInfo(pixel); +}); + +map.on('singleclick', function(evt) { + var pixel = evt.getPixel(); + displayFeatureInfo(pixel); +});