leaflet markercluster add custom icon to all child cluster when a parent cluster is clicked

Viewed 698

I have marker clusters at multiple levels (a child cluster can have clusters and so on).

Now, when I click on a parent cluster, I want to apply a custom icon to all the child clusters of the parent cluster to the bottom of the child clusters.

I tried collecting all child clusters and applying icons to them but it does not work.

cluster.on('clusterclick', (e) => {
  const childClusters = e.layer._childClusters; 
  for(const c of childClusters){
    c.options.icon = this.getSelectedClusterIcon();
  }
});
1 Answers

If I understand correctly, you would like to change the appearance of the "child" clusters of the one that is clicked, i.e. those that appear when you zoom in (but not the individual markers that appear ultimately when zoomed in even further enough)?

In that case, you could rely on the Leaflet.markercluster iconCreateFunction option and refreshClusters method:

  1. Create your MCG with iconCreateFunction that depends on some flags to generate different icons.
  2. In the click event listener, mark all individual child Markers with some sort of flag. You can use the getAllChildMarkers method to retrieve these Markers, as pointed out by Ivan.
  3. Use the refreshClusters method to request MCG to re-evaluate your iconCreateFunction on the parent Clusters of those Markers.
  4. In case you want to change the icon of Clusters that belong only to a certain zoom level (e.g. the one that is clicked, and/or 1 level higher for the immediate child Clusters), you could store those zoom levels in some state, and compare them to the Clusters' _zoom property within the iconCreateFunction.
  5. In case you want to reset the Clusters, simply clear the flags and call again the refreshClusters method.

Something in the lines of:

const mcg = L.markerClusterGroup({
  iconCreateFunction(cluster) {
    const isHighlighted = cluster.getAllChildMarkers().some((marker) => marker.flaggedZooms && marker.flaggedZooms[cluster._zoom]);
    return isHighlighted ? myIconHighlighted : myNormalIcon;
  },
}).on("clusterclick", function (e) {
  // In case we want to reset all other Clusters
  mcg.eachLayer((marker) => delete marker.flaggedZooms);

  const cluster = e.layer;

  // Mark the zoom level on the child Markers,
  // in case we want to change cluster icons only on some zoom
  for (const marker of cluster.getAllChildMarkers()) {
    marker.flaggedZooms = marker.flaggedZooms || {}; // Initialize if not already done
    marker.flaggedZooms[cluster._zoom + 1] = true; // Flag other zoom levels if desired
  }

  // Ensure Clusters icons are redrawn
  mcg.refreshClusters();
});
Related