Is there any way to get all the features in one layer at one specific pixel, including the hidden ones due to decluttering? Currently, when calling Map.getFeaturesAtPixel()
(or Map.forEachFeatureAtPixel()
) those features are omitted.

- 180
- 2
- 12
-
Instead of hiding you could display the features with a minimal opacity such as 0.01 in the rgba setting (definitely works). Or perhaps you could have second style function which does that and do something like `layer.setStyle(tempStyle); var features = map.getFeaturesAtPixel(); layer.setStyle(mainStyle);` but I've not tested that. – Mike Jan 09 '19 at 13:58
-
Thank you @Mike, got me an idea. – Ricardo Jan 18 '19 at 18:12
2 Answers
getFeaturesAtPixel
is designed to report on exactly what's rendered on the map. If you want to get all features at a specific location, you can use ol/source/Vector
's getFeaturesInExtent
method for a small buffer (e.g. 2 pixels) around the coordinate you're interested in:
import {boundingExtent, buffer} from 'ol/extent';
map.on('click', function(e) {
const extent = boundingExtent([e.coordinate]);
buffer(extent, 2 / view.getResolution());
matches = source.getFeaturesInExtent(extent);
});
When you are working with vector tiles, you can achieve the same by first getting the tile
const tileGrid = vectorTileSource.getTileGrid();
const tileCoord = tileGrid.getTileCoordForCoordAndResolution(coordinate, view.getResolution());
const tile = vectorTileSource.getTile(tileCoord);
and then get only the features in your buffer extent:
import {intersects} from 'ol/extent';
const features = tile.getFeatures();
const matches = [];
for (let i = 0, ii = features.length; i < ii; ++i) {
const feature = features[i];
if (intersects(extent, feature.getGeometry().getExtent()) {
matches.push(feature);
}
}

- 5,448
- 15
- 29
-
This code seems to calculate the intersection based on bounding boxes. What I want to know is if the cursor (or the small buffer around the cursor) is actually touching the feature, in the same way getFeaturesAtPixel() works. – Ricardo Jan 18 '19 at 16:41
-
If the feature is not rendered, then the cursor will never touch it. So you have to choose between a graphical way (getFeaturesAtPixel) and an approximate analytical way (code in my answer). You could refine the latter, but it will always be an approximation because you cannot take things like style and icon content into account. – ahocevar Jan 19 '19 at 18:22
-
Thank you @ahocevar. Actually the answer is more complex than I thought because usually you don’t want all the features touching the cursor in all cases (that could lead to a non empty result in an empty area, for example). – Ricardo Jan 19 '19 at 22:25
For the posterity. I think in most cases you don’t need the result to include the hidden features due to decluttering, because that could lead to a non-empty result where the cursor is in an empty area.
What finally did was to create an additional layer without decluttering turned on. Firstly I added there all the features without labels, and hid them simply not setting the fill style (setting the layer opacity to zero would also work). That was giving me great results when an original decluttered feature was overlapping others, but still giving false positives in empty areas.
So finally I decided to show also this new layer behind the decluttered one, with different styling and without labels. This way, visually you can see all the features and decluttered with labels are shown on top, which works perfectly fine also from an UX perspective.

- 180
- 2
- 12