From b42ee8ca0f6a9437a3960e9c4617c161a99694dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Garneau?= Date: Fri, 31 May 2019 14:51:13 -0400 Subject: [PATCH 1/2] Add filter function to translate interaction Add a filter function to the translate interaction. This filter is similar to the one present in the select interaction options and provides the ability to dynamically filter which features to include in the translate interaction. Adding the existing "features" options allows further filtering to take place. In this case the filter is first applied, and features that are passing the filtering need to be present in the "features" options to be further kept. The default filter function always return true (no filtering). --- src/ol/interaction/Translate.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/ol/interaction/Translate.js b/src/ol/interaction/Translate.js index eb2944aa24..7338790b12 100644 --- a/src/ol/interaction/Translate.js +++ b/src/ol/interaction/Translate.js @@ -45,6 +45,10 @@ const TranslateEventType = { * function will be called for each layer in the map and should return * `true` for layers that you want to be translatable. If the option is * absent, all visible layers will be considered translatable. + * @property {FilterFunction} [filter] A function + * that takes an {@link module:ol/Feature} and an + * {@link module:ol/layer/Layer} and returns `true` if the feature may be + * translated or `false` otherwise. * @property {number} [hitTolerance=0] Hit-detection tolerance. Pixels inside the radius around the given position * will be checked for features. */ @@ -136,6 +140,12 @@ class Translate extends PointerInteraction { */ this.layerFilter_ = layerFilter; + /** + * @private + * @type {FilterFunction} + */ + this.filter_ = options.filter ? options.filter : TRUE; + /** * @private * @type {number} @@ -245,9 +255,11 @@ class Translate extends PointerInteraction { */ featuresAtPixel_(pixel, map) { return map.forEachFeatureAtPixel(pixel, - function(feature) { - if (!this.features_ || includes(this.features_.getArray(), feature)) { - return feature; + function(feature, layer) { + if (this.filter_(feature, layer)) { + if (!this.features_ || includes(this.features_.getArray(), feature)) { + return feature; + } } }.bind(this), { layerFilter: this.layerFilter_, From 7817cf31c66169c3299c800327069824b4f877d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Garneau?= Date: Tue, 4 Jun 2019 17:45:28 -0400 Subject: [PATCH 2/2] Changes following code review Add a type for FilterFunction and add tests for filter option. --- src/ol/interaction/Translate.js | 7 ++++ test/spec/ol/interaction/translate.test.js | 41 ++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/ol/interaction/Translate.js b/src/ol/interaction/Translate.js index 7338790b12..b570ed5cca 100644 --- a/src/ol/interaction/Translate.js +++ b/src/ol/interaction/Translate.js @@ -35,6 +35,13 @@ const TranslateEventType = { TRANSLATEEND: 'translateend' }; +/** + * A function that takes an {@link module:ol/Feature} or + * {@link module:ol/render/Feature} and an + * {@link module:ol/layer/Layer} and returns `true` if the feature may be + * translated or `false` otherwise. + * @typedef {function(import("../Feature.js").FeatureLike, import("../layer/Layer.js").default):boolean} FilterFunction + */ /** * @typedef {Object} Options diff --git a/test/spec/ol/interaction/translate.test.js b/test/spec/ol/interaction/translate.test.js index c61f9a30c4..d2b9d41825 100644 --- a/test/spec/ol/interaction/translate.test.js +++ b/test/spec/ol/interaction/translate.test.js @@ -216,6 +216,47 @@ describe('ol.interaction.Translate', function() { }); }); + describe('moving features, with filter option', function() { + let translate; + + beforeEach(function() { + translate = new Translate({ + filter: function(feature, layer) { + return feature == features[0]; + } + }); + map.addInteraction(translate); + }); + + it('moves a filter-passing feature', function() { + const events = trackEvents(features[0], translate); + + simulateEvent('pointermove', 10, 20); + simulateEvent('pointerdown', 10, 20); + simulateEvent('pointerdrag', 50, -40); + simulateEvent('pointerup', 50, -40); + const geometry = features[0].getGeometry(); + expect(geometry).to.be.a(Point); + expect(geometry.getCoordinates()).to.eql([50, 40]); + + validateEvents(events, [features[0]]); + }); + + it('does not move a filter-discarded feature', function() { + const events = trackEvents(features[0], translate); + + simulateEvent('pointermove', 20, 30); + simulateEvent('pointerdown', 20, 30); + simulateEvent('pointerdrag', 50, -40); + simulateEvent('pointerup', 50, -40); + const geometry = features[1].getGeometry(); + expect(geometry).to.be.a(Point); + expect(geometry.getCoordinates()).to.eql([20, -30]); + + expect(events).to.be.empty(); + }); + }); + describe('changes css cursor', function() { let element, translate;