gisopenlayersopenlayers-7

OpenLayers: Remove clusters on certain zoomlevel (even for same coordinates)


I am using OpenLayers 7 and I have a dataset which contains a lot of geojson features which I need to mark on the map. To get an okayish performance I need to cluster them when zoomed out. This works all alright, but the problem is that the dataset contains a lot of data points which have the exact same coordinates.

This results in markers that will never be unclustered. Because the need to be clickable and show a specific icon I wanted to come up with this quick fix:

Whenever the zoomlevel is above a certain amount I would like not to cluster at all any more and show the icons instead. If they are on top of each other I wouldn't care for now.

I tried different ways, for example setting the distance source.setDistance(0) but this does not work, because markers that are at the same point will be clustered even if the distance is set to 0.

I have this code for the clusterSource:

this.clusterLayer = new VectorLayer({
   source: this.clusterSource,
   style: this.clusterStyle,
})
// ...
function clusterStyle(feature) {
  const size = feature.get('features')?.length
  let style = this.styleCache[size]
  const fastLoadingIcon = new Icon({
    src: FastLoadingIcon,
    anchor: [0.5, 1], // bottom center
    scale: 0.75,
  })
  const loadingIcon = new Icon({
    src: LoadingIcon,
    anchor: [0.5, 1], // bottom center
    scale: 0.75,
  })
  if (!style) {
    if (size === 1) {
      return new Style({
        image:
          feature.get('features')[0].get('PowerMap')['75-100kW'] ||
          feature.get('features')[0].get('PowerMap')['100+kW']
            ? fastLoadingIcon
            : loadingIcon,
      })
    }
    style = new Style({
      image: new CircleStyle({
        radius: 11,
        stroke: new Stroke({
          color: '#fff',
        }),
        fill: new Fill({
          color: '#21387D',
        }),
      }),
      text: new Text({
        text: size.toString(),
        fill: new Fill({
          color: '#fff',
        }),
      }),
    })
    this.styleCache[size] = style
  }
  return style
},



I don't fully understand what's going on, but I copied together code from OpenLayers examples, for example from here: https://openlayers.org/en/latest/examples/clusters-dynamic.html

The part where if (size === 1) {.. I can define that I show an icon instead of the cluster.

What I would like to achieve now is that clusters are resolved after a certain zoom level OR I could also imagine that I just show the cluster in another style, showing an icon instead of a circle with a number.


Solution

  • I think your would need separate clustered and unclustered layers.

    You could control visibility via minZoom and maxZoom options

    clusterSource = new ClusterSource({
      source: source,
    });
    layer = new VectorLayer({
      source: source,
      minZoom: limit,
    });
    clusterLayer = new VectorLayer({
      source: clusterSource,
      maxZoom: limit,
    });
    

    or by checking resolution in the style functions, e.g.

    function(feature, resolution) {
      if (resolution < map.getView().getResolutionForZoom(limit)) {
        return;
      }
      return style;
    }