diff --git a/externs/olx.js b/externs/olx.js index dd785b1bee..1789574ec3 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -2602,7 +2602,8 @@ olx.interaction.PointerOptions.prototype.handleUpEvent; * style: (ol.style.Style|Array.|ol.style.StyleFunction|undefined), * removeCondition: (ol.events.ConditionType|undefined), * toggleCondition: (ol.events.ConditionType|undefined), - * multi: (boolean|undefined)}} + * multi: (boolean|undefined), + * filter: (ol.interaction.SelectFilterFunction|undefined)}} * @api */ olx.interaction.SelectOptions; @@ -2688,6 +2689,14 @@ olx.interaction.SelectOptions.prototype.toggleCondition; */ olx.interaction.SelectOptions.prototype.multi; +/** + * A function that takes an {@link ol.Feature} and an {@link ol.layer.Layer} and + * returns `true` if the feature may be selected or `false` otherwise. + * @type {ol.interaction.SelectFilterFunction|undefined} + * @api + */ +olx.interaction.SelectOptions.prototype.filter; + /** * Options for snap diff --git a/src/ol/interaction/selectinteraction.js b/src/ol/interaction/selectinteraction.js index c205f65f23..9e1c16a638 100644 --- a/src/ol/interaction/selectinteraction.js +++ b/src/ol/interaction/selectinteraction.js @@ -27,6 +27,15 @@ ol.SelectEventType = { }; +/** + * A function that takes an {@link ol.Feature} and an {@link ol.layer.Layer} + * and returns `true` if the feature may be selected or `false` otherwise. + * @typedef {function(ol.Feature, ol.layer.Layer): boolean} + * @api + */ +ol.interaction.SelectFilterFunction; + + /** * @classdesc @@ -115,6 +124,13 @@ ol.interaction.Select = function(opt_options) { */ this.multi_ = goog.isDef(options.multi) ? options.multi : false; + /** + * @private + * @type {ol.interaction.SelectFilterFunction} + */ + this.filter_ = goog.isDef(options.filter) ? options.filter : + goog.functions.TRUE; + var layerFilter; if (goog.isDef(options.layers)) { if (goog.isFunction(options.layers)) { @@ -198,7 +214,9 @@ ol.interaction.Select.handleEvent = function(mapBrowserEvent) { * @param {ol.layer.Layer} layer Layer. */ function(feature, layer) { - selected.push(feature); + if (this.filter_(feature, layer)) { + selected.push(feature); + } return !this.multi_; }, this, this.layerFilter_); if (selected.length > 0 && features.getLength() == 1 && @@ -223,14 +241,16 @@ ol.interaction.Select.handleEvent = function(mapBrowserEvent) { var index = goog.array.indexOf(features.getArray(), feature); if (index == -1) { if (add || toggle) { - selected.push(feature); + if (this.filter_(feature, layer)) { + selected.push(feature); + } } } else { if (remove || toggle) { deselected.push(feature); } } - }, undefined, this.layerFilter_); + }, this, this.layerFilter_); var i; for (i = deselected.length - 1; i >= 0; --i) { features.remove(deselected[i]); diff --git a/test/spec/ol/interaction/selectinteraction.test.js b/test/spec/ol/interaction/selectinteraction.test.js index d0aaf4f85a..4d3278fe79 100644 --- a/test/spec/ol/interaction/selectinteraction.test.js +++ b/test/spec/ol/interaction/selectinteraction.test.js @@ -2,12 +2,14 @@ goog.provide('ol.test.interaction.Select'); describe('ol.interaction.Select', function() { var target, map, source; + var feature1, feature2; var width = 360; var height = 180; beforeEach(function(done) { target = document.createElement('div'); + var style = target.style; style.position = 'absolute'; style.left = '-1000px'; @@ -15,18 +17,25 @@ describe('ol.interaction.Select', function() { style.width = width + 'px'; style.height = height + 'px'; document.body.appendChild(target); - var geometry = new ol.geom.Polygon([[[0, 0], [0, 40], [40, 40], [40, 0]]]); + + var geometry1 = new ol.geom.Polygon([[[0, 0], [0, 40], [40, 40], [40, 0]]]); var geometry2 = new ol.geom.Polygon([[[0, 0], [0, 40], [40, 40], [40, 0]]]); - var feature = new ol.Feature({ - geometry: geometry + + feature1 = new ol.Feature({ + geometry: geometry1 }); - var feature2 = new ol.Feature({ + feature1.setId('fid1'); + + feature2 = new ol.Feature({ geometry: geometry2 }); + feature2.setId('fid2'); + source = new ol.source.Vector({ - features: [feature, feature2] + features: [feature1, feature2] }); var layer = new ol.layer.Vector({source: source}); + map = new ol.Map({ target: target, layers: [layer], @@ -36,6 +45,7 @@ describe('ol.interaction.Select', function() { resolution: 1 }) }); + map.on('postrender', function() { done(); }); @@ -127,6 +137,45 @@ describe('ol.interaction.Select', function() { }); }); + describe.only('filter out features using the filter option', function() { + var select; + + describe('with multi set to true', function() { + + it('does not select features that are filtered out', function() { + var select = new ol.interaction.Select({ + multi: true, + filter: function(feature, layer) { + return feature.getId() !== 'fid2'; + } + }); + map.addInteraction(select); + + simulateEvent(ol.MapBrowserEvent.EventType.SINGLECLICK, 10, -20); + var features = select.getFeatures(); + expect(features.getLength()).to.equal(1); + expect(features.item(0).getId()).not.to.be('fid2'); + }); + }); + + describe('with multi set to false', function() { + + it('does not select features that are filtered out', function() { + var select = new ol.interaction.Select({ + multi: false, + filter: function(feature, layer) { + return feature.getId() !== 'fid2'; + } + }); + map.addInteraction(select); + simulateEvent(ol.MapBrowserEvent.EventType.SINGLECLICK, 10, -20); + var features = select.getFeatures(); + expect(features.getLength()).to.equal(0); + }); + }); + + }); + describe('#setActive()', function() { var interaction;