From 05ceaab6207d6384328043b8e963ea646b8a0c4f Mon Sep 17 00:00:00 2001 From: Frederic Junod Date: Tue, 12 Apr 2016 11:43:46 +0200 Subject: [PATCH] Add an optional feature filter to getClosestFeatureToCoordinate --- src/ol/source/vectorsource.js | 42 ++++++++++++++---------- test/spec/ol/source/vectorsource.test.js | 32 ++++++++++++++++++ 2 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/ol/source/vectorsource.js b/src/ol/source/vectorsource.js index b00d7acefa..14b74263df 100644 --- a/src/ol/source/vectorsource.js +++ b/src/ol/source/vectorsource.js @@ -612,10 +612,13 @@ ol.source.Vector.prototype.getFeaturesInExtent = function(extent) { * This method is not available when the source is configured with * `useSpatialIndex` set to `false`. * @param {ol.Coordinate} coordinate Coordinate. + * @param {function(ol.Feature):boolean=} opt_filter Feature filter function. + * The filter function will receive one argument, the {@link ol.Feature feature} + * and it should return a boolean value. By default, no filtering is made. * @return {ol.Feature} Closest feature. * @api stable */ -ol.source.Vector.prototype.getClosestFeatureToCoordinate = function(coordinate) { +ol.source.Vector.prototype.getClosestFeatureToCoordinate = function(coordinate, opt_filter) { // Find the closest feature using branch and bound. We start searching an // infinite extent, and find the distance from the first feature found. This // becomes the closest feature. We then compute a smaller extent which any @@ -632,28 +635,31 @@ ol.source.Vector.prototype.getClosestFeatureToCoordinate = function(coordinate) goog.asserts.assert(this.featuresRtree_, 'getClosestFeatureToCoordinate does not work with useSpatialIndex set ' + 'to false'); + var filter = opt_filter ? opt_filter : ol.functions.TRUE; this.featuresRtree_.forEachInExtent(extent, /** * @param {ol.Feature} feature Feature. */ function(feature) { - var geometry = feature.getGeometry(); - goog.asserts.assert(geometry, - 'feature geometry is defined and not null'); - var previousMinSquaredDistance = minSquaredDistance; - minSquaredDistance = geometry.closestPointXY( - x, y, closestPoint, minSquaredDistance); - if (minSquaredDistance < previousMinSquaredDistance) { - closestFeature = feature; - // This is sneaky. Reduce the extent that it is currently being - // searched while the R-Tree traversal using this same extent object - // is still in progress. This is safe because the new extent is - // strictly contained by the old extent. - var minDistance = Math.sqrt(minSquaredDistance); - extent[0] = x - minDistance; - extent[1] = y - minDistance; - extent[2] = x + minDistance; - extent[3] = y + minDistance; + if (filter(feature)) { + var geometry = feature.getGeometry(); + goog.asserts.assert(geometry, + 'feature geometry is defined and not null'); + var previousMinSquaredDistance = minSquaredDistance; + minSquaredDistance = geometry.closestPointXY( + x, y, closestPoint, minSquaredDistance); + if (minSquaredDistance < previousMinSquaredDistance) { + closestFeature = feature; + // This is sneaky. Reduce the extent that it is currently being + // searched while the R-Tree traversal using this same extent object + // is still in progress. This is safe because the new extent is + // strictly contained by the old extent. + var minDistance = Math.sqrt(minSquaredDistance); + extent[0] = x - minDistance; + extent[1] = y - minDistance; + extent[2] = x + minDistance; + extent[3] = y + minDistance; + } } }); return closestFeature; diff --git a/test/spec/ol/source/vectorsource.test.js b/test/spec/ol/source/vectorsource.test.js index 1ec4667cbc..46dfaebbc2 100644 --- a/test/spec/ol/source/vectorsource.test.js +++ b/test/spec/ol/source/vectorsource.test.js @@ -77,6 +77,37 @@ describe('ol.source.Vector', function() { }); + describe('when populated with 3 features', function() { + + var features = []; + var vectorSource; + beforeEach(function() { + features.push(new ol.Feature(new ol.geom.LineString([[0, 0], [10, 10]]))); + features.push(new ol.Feature(new ol.geom.Point([0, 10]))); + features.push(new ol.Feature(new ol.geom.Point([10, 5]))); + vectorSource = new ol.source.Vector({ + features: features + }); + }); + + describe('#getClosestFeatureToCoordinate', function() { + + it('returns the expected feature', function() { + var feature = vectorSource.getClosestFeatureToCoordinate([1, 9]); + expect(feature).to.be(features[1]); + }); + + it('returns the expected feature when a filter is used', function() { + var feature = vectorSource.getClosestFeatureToCoordinate([1, 9], function(feature) { + return feature.getGeometry().getType() == 'LineString'; + }); + expect(feature).to.be(features[0]); + }); + + }); + + }); + describe('when populated with 10 random points and a null', function() { var features; @@ -558,5 +589,6 @@ goog.require('ol.events'); goog.require('ol.Collection'); goog.require('ol.Feature'); goog.require('ol.geom.Point'); +goog.require('ol.geom.LineString'); goog.require('ol.proj'); goog.require('ol.source.Vector');