4

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.

Community
  • 1
  • 1
Abu Sulaiman
  • 1,477
  • 2
  • 18
  • 32
  • 1
    Thx for the clarification of your requirement. It sounds to me that you should request more details on the "_markers in category 1 must cluster separately from markers in category 2_". E.g. what should happen if you have marker A from cat 1 at exact same position as marker B from cat 2? With current code they will just overlap (not even cluster). Sounds like poor UI to me. – ghybs Sep 21 '18 at 13:35
  • Yeah, I'm already seeing that happen. I'm taking your advice and going back to get more clarification, especially for when the markers are in the exact position. Thanks for your help. – Abu Sulaiman Sep 21 '18 at 14:07

1 Answers1

6

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/leaflet@1.3.4/dist/leaflet.css" integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA==" crossorigin="" />
<script src="https://unpkg.com/leaflet@1.3.4/dist/leaflet-src.js" integrity="sha512-+ZaXMZ7sjFMiCigvm8WjllFy6g3aou3+GZngAtugLzrmPFKFK7yjSri0XnElvCTu/PrifAYQuxZTybAEkA8VOA==" crossorigin=""></script>

<!-- Leaflet.markercluster assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.4.1/dist/MarkerCluster.Default.css">
<script src="https://unpkg.com/leaflet.markercluster@1.4.1/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.

Community
  • 1
  • 1
ghybs
  • 47,565
  • 6
  • 74
  • 99
  • 1
    And there's an interesting degenerate case: What if there are four data points, two for each category, in the same exact coordinates? – IvanSanchez Sep 21 '18 at 08:04
  • I added the requirement to the question. I would appreciate it very much if you could point me in the direction of other libraries or workarounds. Thank you very much. – Abu Sulaiman Sep 21 '18 at 13:33
  • I see what your saying @IvanSanchez. – Abu Sulaiman Sep 21 '18 at 13:33
  • @AbuSulaiman: added link to alternative PruneCluster, and example of customized cluster icon to show different categories. – ghybs Sep 23 '18 at 02:42
  • @ghybs Thanks for the link and example. I have never come across PruneCluster. It is really cool and I think its exactly what we are looking for. It may take a while to change out but I think it will be worth it. Thank you so much. This is great! – Abu Sulaiman Sep 24 '18 at 00:47
  • @ghybs Your MarkerCluster example is good too. Now i have options, thanks again! – Abu Sulaiman Sep 24 '18 at 18:53