0

I am using OpenLayers v7.5 to display point features with icons and labels on a VectorLayer. To prevent label overlap, I enabled declutter: true, but this causes both icons and labels to disappear in crowded areas.

What I Need: Labels should declutter (hide overlapping text) when zooming out.

Icons should always remain visible, even if their corresponding label is hidden.

Current Implementation:

const layer = new ol.layer.Vector({
    source: vectorSource,
    style: new ol.style.Style({
        image: new ol.style.Icon({
            src: 'pin.png',
        }),
        text: new ol.style.Text({
            text: feature.get('name'),
        }),
    }),
    declutter: true, // Hides BOTH icons and labels
});

With this setup, both icons and labels disappear when overlapping occurs.

What I've Tried:

  • Setting declutter: true on a layer with both icons and labels results in both disappearing.

  • Using two separate layers (one for icons, one for labels) is not feasible for us.

  • Applying overflow: true on ol.style.Text does not prevent the issue.

Questions:

  1. How can I declutter only labels while ensuring icons always remain visible?

  2. Is there a way to configure OpenLayers to handle decluttering separately for text and images?

1 Answer 1

0

'declutter' gets applied to layer level. When you put image style and text style for the feature and set declutter=true, then OpenLayers applies it to all styles to avoid overlaps. The way to overcome this is to set the label text style to a separate layer with the same source. This way you can set declutter=true, exclusively to the label layer. It will also comes in handy when you want to turn on or off labels. When setting a style to the label layer, you can build a style function. Here is how I do it -

const layer =  new ol.layer.Vector({
source: vectorSource,
 style:new ol.style.Style({
        image: new ol.style.Icon({
            src: 'pin.png',
        }),
 });
map.addLayer(layer);

function labelStyle(feature) {
  label = feature.get('name');
 return new ol.style.Style({
  text: new ol.style.Text({
  font: '13px Calibri,sans-serif',
   text: label,  
    fill: new ol.style.Fill({ color: '#000' }),
    stroke: new ol.style.Stroke({ color: '#fff', width: 2 }),
     offsetY: '-15', // I am setting this offset so that I can clearly see both style and the labels
   })
  });
}

var labelLayer = new ol.layer.Vector({
 source: vectorSource,
 style: labelStyle,
 declutter: true
});

map.addLayer(labelLayer)

When you want to turn off the label, you can either remove label layer from the map OR you can set text to ''.

Sign up to request clarification or add additional context in comments.

1 Comment

Also, you said that adding a separate layer is not feasible for you. In terms of what becomes visible on map, if you set label style only to text not with image or icon then it just becomes a label. If your workflow automatically adds loaded layer to table of contents (layer switcher) or generates legend etc, then you can exclusively set something like labelLayer.set('labelApplied', true). Then you can always check 'if layer.get('labelApplied')....'. This way if you get 'true' then you can exclude the layer from appearing on TOC or legend images etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.