diff --git a/src/ol/interaction/selectinteraction.js b/src/ol/interaction/selectinteraction.js index a5a0ec93a3..a14e0bf9a7 100644 --- a/src/ol/interaction/selectinteraction.js +++ b/src/ol/interaction/selectinteraction.js @@ -97,6 +97,8 @@ goog.inherits(ol.interaction.SelectEvent, goog.events.Event); * `toggle`, `add`/`remove`, and `multi` options; a `layers` filter; and a * further feature filter using the `filter` option. * + * Selected features are added to an internal unmanaged layer. + * * @constructor * @extends {ol.interaction.Interaction} * @param {olx.interaction.SelectOptions=} opt_options Options. diff --git a/src/ol/layer/layer.js b/src/ol/layer/layer.js index 559e72105f..db372eec36 100644 --- a/src/ol/layer/layer.js +++ b/src/ol/layer/layer.js @@ -20,6 +20,11 @@ goog.require('ol.source.State'); * Layers group together those properties that pertain to how the data is to be * displayed, irrespective of the source of that data. * + * Layers are usually added to a map with {@link ol.Map#addLayer}. Components + * like {@link ol.interaction.Select} use unmanaged layers internally. These + * unmanaged layers are associated with the map using + * {@link ol.layer.Layer#setMap} instead. + * * A generic `change` event is fired when the state of the source changes. * * @constructor diff --git a/src/ol/map.js b/src/ol/map.js index 91f02c0481..70a75dc2fa 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -599,8 +599,9 @@ ol.Map.prototype.disposeInternal = function() { * called with two arguments. The first argument is one * {@link ol.Feature feature} or * {@link ol.render.Feature render feature} at the pixel, the second is - * the {@link ol.layer.Layer layer} of the feature. To stop detection, - * callback functions can return a truthy value. + * the {@link ol.layer.Layer layer} of the feature and will be null for + * unmanaged layers. To stop detection, callback functions can return a + * truthy value. * @param {S=} opt_this Value to use as `this` when executing `callback`. * @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer * filter function. The filter function will receive one argument, the diff --git a/src/ol/renderer/maprenderer.js b/src/ol/renderer/maprenderer.js index de5a49d80d..36bf4af4e5 100644 --- a/src/ol/renderer/maprenderer.js +++ b/src/ol/renderer/maprenderer.js @@ -174,7 +174,9 @@ ol.renderer.Map.prototype.forEachFeatureAtCoordinate = if (layer.getSource()) { result = layerRenderer.forEachFeatureAtCoordinate( layer.getSource().getWrapX() ? translatedCoordinate : coordinate, - frameState, callback, thisArg); + frameState, + layerState.managed ? callback : forEachFeatureAtCoordinate, + thisArg); } if (result) { return result; diff --git a/test/spec/ol/renderer/canvas/canvasmaprenderer.test.js b/test/spec/ol/renderer/canvas/canvasmaprenderer.test.js index 5943961f16..dec7879807 100644 --- a/test/spec/ol/renderer/canvas/canvasmaprenderer.test.js +++ b/test/spec/ol/renderer/canvas/canvasmaprenderer.test.js @@ -46,13 +46,23 @@ describe('ol.renderer.canvas.Map', function() { document.body.removeChild(target); }); - it('always includes unmanaged layers', function() { + it('calls callback with layer for managed layers', function() { + map.addLayer(layer); + map.renderSync(); + var cb = sinon.spy(); + map.forEachFeatureAtPixel(map.getPixelFromCoordinate([0, 0]), cb); + expect(cb).to.be.called(); + expect(cb.firstCall.args[1]).to.be(layer); + }); + + it('includes unmanaged layers, but calls callback with null', function() { layer.setMap(map); map.renderSync(); var cb = sinon.spy(); map.forEachFeatureAtPixel(map.getPixelFromCoordinate([0, 0]), cb, null, function() { return false; }); expect(cb).to.be.called(); + expect(cb.firstCall.args[1]).to.be(null); }); it('filters managed layers', function() {