From c81dfdc69bbba21adc3e61477bd6cdb899b181b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Mon, 18 Aug 2014 10:24:12 +0200 Subject: [PATCH] Do not hit-detect the same feature multiple times In other words forEachFeatureAtPixel should not call the user-provided callback more than once for a given feature. --- .../canvas/canvasvectorlayerrenderer.js | 8 +++- src/ol/source/imagevectorsource.js | 9 ++++- .../canvas/canvasvectorlayerrenderer.test.js | 38 +++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/ol/renderer/canvas/canvasvectorlayerrenderer.js b/src/ol/renderer/canvas/canvasvectorlayerrenderer.js index faebd6bc7e..f54f5fbf6e 100644 --- a/src/ol/renderer/canvas/canvasvectorlayerrenderer.js +++ b/src/ol/renderer/canvas/canvasvectorlayerrenderer.js @@ -121,6 +121,8 @@ ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtPixel = var resolution = frameState.viewState.resolution; var rotation = frameState.viewState.rotation; var layer = this.getLayer(); + /** @type {Object.} */ + var features = {}; return this.replayGroup_.forEachGeometryAtPixel(extent, resolution, rotation, coordinate, frameState.skippedFeatureUids, /** @@ -131,7 +133,11 @@ ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtPixel = function(geometry, data) { var feature = /** @type {ol.Feature} */ (data); goog.asserts.assert(goog.isDef(feature)); - return callback.call(thisArg, feature, layer); + var key = goog.getUid(feature).toString(); + if (!(key in features)) { + features[key] = true; + return callback.call(thisArg, feature, layer); + } }); } }; diff --git a/src/ol/source/imagevectorsource.js b/src/ol/source/imagevectorsource.js index b9a7e44bbd..59c366133f 100644 --- a/src/ol/source/imagevectorsource.js +++ b/src/ol/source/imagevectorsource.js @@ -148,6 +148,8 @@ ol.source.ImageVector.prototype.forEachFeatureAtPixel = function( if (goog.isNull(this.replayGroup_)) { return undefined; } else { + /** @type {Object.} */ + var features = {}; return this.replayGroup_.forEachGeometryAtPixel( extent, resolution, 0, coordinate, skippedFeatureUids, /** @@ -157,7 +159,12 @@ ol.source.ImageVector.prototype.forEachFeatureAtPixel = function( */ function(geometry, data) { var feature = /** @type {ol.Feature} */ (data); - return callback(feature); + goog.asserts.assert(goog.isDef(feature)); + var key = goog.getUid(feature).toString(); + if (!(key in features)) { + features[key] = true; + return callback(feature); + } }); } }; diff --git a/test/spec/ol/renderer/canvas/canvasvectorlayerrenderer.test.js b/test/spec/ol/renderer/canvas/canvasvectorlayerrenderer.test.js index ada7c28f77..2b644eeeeb 100644 --- a/test/spec/ol/renderer/canvas/canvasvectorlayerrenderer.test.js +++ b/test/spec/ol/renderer/canvas/canvasvectorlayerrenderer.test.js @@ -58,6 +58,44 @@ describe('ol.renderer.canvas.VectorLayer', function() { }); + describe('#forEachFeatureAtPixel', function() { + var renderer; + + beforeEach(function() { + var map = new ol.Map({}); + var layer = new ol.layer.Vector({ + source: new ol.source.Vector() + }); + renderer = new ol.renderer.canvas.VectorLayer( + map.getRenderer(), layer); + var replayGroup = {}; + renderer.replayGroup_ = replayGroup; + replayGroup.forEachGeometryAtPixel = function(extent, resolution, + rotation, coordinate, skippedFeaturesUids, callback) { + var geometry = new ol.geom.Point([0, 0]); + var feature = new ol.Feature(); + callback(geometry, feature); + callback(geometry, feature); + }; + }); + + it('calls callback once per feature', function() { + var spy = sinon.spy(); + var coordinate = [0, 0]; + var frameState = { + extent: [1, 1, 10, 10], + skippedFeatureUids: {}, + viewState: { + resolution: 1, + rotation: 0 + } + }; + renderer.forEachFeatureAtPixel( + coordinate, frameState, spy, undefined); + expect(spy.callCount).to.be(1); + }); + }); + });