Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent multiple markerClusterGroup icons from overlapping in Leaflet

I have two seperate markerClusterGroups that occasionally overlap. Is there anyway to prevent this? In my actual code, I am using a custom Icon for one of the cluster groups so that I can tell the difference between the two cluster types. However, it wasn't neccessary for this example so I left that part out for the sake of simplicity.

var map = L.map("map");

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

map.setView([48.85, 2.35], 12);
var mcg = L.markerClusterGroup().addTo(map);
var mcg2 = L.markerClusterGroup().addTo(map);

L.marker([48.85, 2.35]).addTo(mcg);
L.marker([48.85, 2.34]).addTo(mcg);
  
for(var i=0;i<40;i++){
    L.marker([48.85, 2.34091]).addTo(mcg2);
}

Here is an example of what I mean:

http://plnkr.co/edit/yqIhI7RMsp9A7I3AwGnY?p=preview

Screenshot

The requirement states that the markers in category 1 must cluster separately from markers in category 2. However both types must be displayed on the map at the same time.

like image 606
Abu Sulaiman Avatar asked Nov 05 '25 02:11

Abu Sulaiman


1 Answers

Is there anyway to prevent this?

Not with several Leaflet.markercluster groups as you did.

Think about it: where should the cluster icons positions be computed, when a given group has no data about another group?

You may have several possible workarounds and/or other libraries that may better fit your need, without having to re-write a clustering algorithm yourself.

For example, a popular alternative to show different categories while clustering is the PruneCluster plugin:

PruneCluster is a fast and realtime marker clustering library.

It's working with Leaflet as an alternative to Leaflet.markercluster.

Screenshot of map with PruneCluster icon categories Excerpt from PruneCluster home page

Another possible workaround would be to merge all categories into the same Marker Cluster Group, but have the latter's cluster icon customized so that they render similarly as the above PruneCluster screenshot, or even render fake icons for each category:

Screenshot of Leaflet.markercluster with customized cluster icons for each category

function customClusterIcon(cluster) {
  // Count number of markers from each category.
  var markers = cluster.getAllChildMarkers();
  var cat1count = 0;
  var cat2count = 0;
  for (var marker of markers) {
    var category = marker.options.category;
    if (category && category === 'cat2') {
      cat2count += 1;
    } else {
      cat1count += 1;
    }
  }
  // Generate the cluster icon depending on presence of Markers from different categories.
  if (cat2count === 0) {
    return L.divIcon({
      html: cat1count,
      className: 'cat1cluster cluster',
      iconSize: [20, 20]
    });
  } else if (cat1count === 0) {
    return L.divIcon({
      html: cat2count,
      className: 'cat2cluster cluster',
      iconSize: [20, 20]
    });
  } else {
    return L.divIcon({
      html: `
        <div class="cat1cluster cluster">${cat1count}</div>
        <div class="cat2cluster cluster">${cat2count}</div>
      `,
      className: '',
      iconSize: [45, 20]
    });
  }
}

var paris = [48.86, 2.35];
var parisLeft = [48.86, 2.25];
var parisRight = [48.86, 2.45];
var map = L.map('map', {
  maxZoom: 18
}).setView(paris, 11);

var mcg = L.markerClusterGroup({
  iconCreateFunction: customClusterIcon
}).addTo(map);
var category1 = L.layerGroup();
var category2 = L.layerGroup();

var cat2style = {
  color: 'red',
  category: 'cat2'
};

var markerA = L.circleMarker(paris).addTo(category1);
var markerB = L.circleMarker(paris).addTo(category1);
var markerC = L.circleMarker(paris, cat2style).addTo(category2);
var markerD = L.circleMarker(paris, cat2style).addTo(category2);

var markerE = L.circleMarker(parisLeft).addTo(category1);
var markerF = L.circleMarker(parisLeft).addTo(category1);

var markerG = L.circleMarker(parisRight, cat2style).addTo(category2);
var markerH = L.circleMarker(parisRight, cat2style).addTo(category2);

mcg.addLayers([category1, category2]);


L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
html,
body,
#map {
  height: 100%;
  margin: 0;
}

.cat1cluster {
  background-color: #3388ff;
}

.cat2cluster {
  background-color: red;
}

.cluster {
  width: 20px;
  height: 20px;
  display: inline-block;
  text-align: center;
}
<!-- Leaflet assets -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA==" crossorigin="" />
<script src="https://unpkg.com/[email protected]/dist/leaflet-src.js" integrity="sha512-+ZaXMZ7sjFMiCigvm8WjllFy6g3aou3+GZngAtugLzrmPFKFK7yjSri0XnElvCTu/PrifAYQuxZTybAEkA8VOA==" crossorigin=""></script>

<!-- Leaflet.markercluster assets -->
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/MarkerCluster.css">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/MarkerCluster.Default.css">
<script src="https://unpkg.com/[email protected]/dist/leaflet.markercluster-src.js"></script>


<div id="map"></div>

Then if you wish you can further customize the spiderfication so that it shows Markers only from the clicked category cluster icon, and similar for the hovering polygon.

like image 156
ghybs Avatar answered Nov 06 '25 17:11

ghybs



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!