diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index 811a0bf6ce..1dc393a348 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -394,6 +394,25 @@ * @todo stability experimental */ +/** + * @typedef {Object} olx.interaction.SelectOptions + * @property {ol.events.ConditionType|undefined} addCondition A conditional + * modifier (e.g. shift key) that determines if the selection is added to + * the current selection. By default, a shift-click adds to the current + * selection. + * @property {ol.events.ConditionType|undefined} condition A conditional + * modifier (e.g. shift key) that determines if the interaction is active + * (i.e. selection occurs) or not. By default, a click with no modifier keys + * toggles the selection. + * @property {function(ol.layer.Layer): boolean|undefined} layerFilter Filter + * function to restrict selection to a subset of layers. + * @property {ol.layer.Layer|undefined} layer Layer. The single layer from which + * features should be selected. + * @property {Array.|undefined} layers Layers. Zero or more + * layers from which features should be selected. + * @property {ol.render.FeaturesOverlay} featuresOverlay Features overlay. + */ + /** * @typedef {Object} olx.interaction.TouchPanOptions * @property {ol.Kinetic|undefined} kinetic Kinetic inertia to apply to the diff --git a/src/ol/interaction/selectinteraction.exports b/src/ol/interaction/selectinteraction.exports new file mode 100644 index 0000000000..2f926953a1 --- /dev/null +++ b/src/ol/interaction/selectinteraction.exports @@ -0,0 +1,3 @@ +@exportSymbol ol.interaction.Select +@exportProperty ol.interaction.Select.prototype.getFeaturesOverlay +@exportProperty ol.interaction.Select.prototype.setMap diff --git a/src/ol/interaction/selectinteraction.js b/src/ol/interaction/selectinteraction.js new file mode 100644 index 0000000000..8eb16eef06 --- /dev/null +++ b/src/ol/interaction/selectinteraction.js @@ -0,0 +1,141 @@ +goog.provide('ol.interaction.Select'); + +goog.require('goog.array'); +goog.require('goog.functions'); +goog.require('ol.events.condition'); +goog.require('ol.interaction.Interaction'); +goog.require('ol.render.FeaturesOverlay'); + + + +/** + * @constructor + * @extends {ol.interaction.Interaction} + * @param {olx.interaction.SelectOptions=} opt_options Options. + */ +ol.interaction.Select = function(opt_options) { + + var options = goog.isDef(opt_options) ? opt_options : {}; + + goog.base(this); + + /** + * @private + * @type {ol.events.ConditionType} + */ + this.condition_ = goog.isDef(options.condition) ? + options.condition : ol.events.condition.singleClick; + + /** + * @private + * @type {ol.events.ConditionType} + */ + this.addCondition_ = goog.isDef(options.addCondition) ? + options.addCondition : ol.events.condition.shiftKeyOnly; + + var layerFilter; + if (goog.isDef(options.layerFilter)) { + layerFilter = options.layerFilter; + } else if (goog.isDef(options.layer)) { + var layer = options.layer; + layerFilter = function(l) { + return l === layer; + }; + } else if (goog.isDef(options.layers)) { + var layers = options.layers; + layerFilter = function(layer) { + return goog.array.indexOf(layers, layer) != -1; + }; + } else { + layerFilter = goog.functions.TRUE; + } + + /** + * @private + * @type {function(ol.layer.Layer): boolean} + */ + this.layerFilter_ = layerFilter; + + /** + * @private + * @type {ol.render.FeaturesOverlay} + */ + this.featuresOverlay_ = options.featuresOverlay; + +}; +goog.inherits(ol.interaction.Select, ol.interaction.Interaction); + + +/** + * @return {ol.render.FeaturesOverlay} Features overlay. + */ +ol.interaction.Select.prototype.getFeaturesOverlay = function() { + return this.featuresOverlay_; +}; + + +/** + * @inheritDoc + */ +ol.interaction.Select.prototype.handleMapBrowserEvent = + function(mapBrowserEvent) { + if (!this.condition_(mapBrowserEvent)) { + return true; + } + var add = this.addCondition_(mapBrowserEvent); + var map = mapBrowserEvent.map; + var features = this.featuresOverlay_.getFeatures(); + map.withFrozenRendering( + /** + * @this {ol.interaction.Select} + */ + function() { + if (add) { + map.forEachFeatureAtPixel(mapBrowserEvent.getPixel(), + /** + * @param {ol.Feature} feature Feature. + * @param {ol.layer.Layer} layer Layer. + */ + function(feature, layer) { + if (goog.array.indexOf(features.getArray(), feature) == -1) { + features.push(feature); + } + }, undefined, this.layerFilter_); + } else { + var feature = map.forEachFeatureAtPixel(mapBrowserEvent.getPixel(), + /** + * @param {ol.Feature} feature Feature. + * @param {ol.layer.Layer} layer Layer. + */ + function(feature, layer) { + return feature; + }, undefined, this.layerFilter_); + if (goog.isDef(feature)) { + if (features.getLength() == 1) { + if (features.getAt(0) !== feature) { + features.setAt(0, feature); + } + } else { + if (features.getLength() != 1) { + features.clear(); + } + features.push(feature); + } + } else { + if (features.getLength() !== 0) { + features.clear(); + } + } + } + }, this); + return false; +}; + + +/** + * @inheritDoc + */ +ol.interaction.Select.prototype.setMap = function(map) { + goog.base(this, 'setMap', map); + this.featuresOverlay_.setMap(map); +};