On a custom leaflet map, I am trying to build a function to fill the background color of a cluster icon from the color of the markers that are inside the cluster. For example, if a cluster has 7 green markers and 2 red markers, fill the cluster at 77% green and else in red.
I'm using markerCluster plugin, and awesome marker plugin together.
For the moment, here is what I have :
var clusters = L.markerClusterGroup({
spiderfyOnMaxZoom: false,
showCoverageOnHover: false,
zoomToBoundsOnClick: true,
iconCreateFunction: function (cluster) {
var markers = cluster.getAllChildMarkers();
console.log(markers);
markers.forEach(function (m) {
var color = m.defaultOptions.icon.options.markerColor;
console.log(color);
});
var html =
'<span class="circle circle-' + markers[0].feature.properties["Examen"] +
'">' + markers.length + "</span>";
return L.divIcon({ html: html, className: "marker-cluster", iconSize: L.point(32, 32) });
},
});
I see that I can get the number of markers inside each cluster and the associated color, something like this.
So my question is, from this, how can I loop through "color" to get the percentage of each color inside the cluster ?
My goal is then to use this percentage to fill the background color of the cluster..to get something like this ?
I saw many example about this, like here here here here and here but I wonder if I cannot have something similar without tons of complicated code like in those examples ?
EDIT:
Ok so thanks to the kind help of @IvanSanchez, I reproduced the provided code into my project and it is working ! I had to change it a little bit to make it work and I tried with icon-gradient and linear gradient.
Below is my final culsterGroup function and I show a full example of the two versions here (iconic css) and here ( linear-gradient). I'm sorry I cannot post it here as the code is too long for this editor :)
Once implemented, I made some changes. - Because I was getting only the first letter of my colors, the css was not working. So I wrote :
stops.push(color + ' ' + startPercent + '%');
stops.push(color + ' ' + endPercent + '%');
instead of
stops.push(color[i] + ' ' + startPercent + '%');
stops.push(color[i] + ' ' + endPercent + '%');
I also had to change my span in the 'html' var by a div, as the marker-cluster css is applied on div by default.
var clusters = L.markerClusterGroup({ spiderfyOnMaxZoom: false, showCoverageOnHover: false, zoomToBoundsOnClick: true,
iconCreateFunction: function (cluster) { var markers = cluster.getAllChildMarkers(); var childCount = cluster.getChildCount(); console.log(markers); var stops = []; for (let i=0, l=markers.length; i<l; i++) { var color = markers[i].defaultOptions.icon.options.markerColor; let startPercent = 100 * (i/l); let endPercent = 100 * (i+1)/l; stops.push(color + ' ' + startPercent + '%'); stops.push(color + ' ' + endPercent + '%'); } var html = '<div class="circleMarker" style="background: linear-gradient(to right,' + stops.join(',') + '" >' + markers.length + "</div>"; return L.divIcon({ html: html, className: "marker-cluster", iconSize: L.point(40, 40) }); }, });
Also, some mixtures of colors no longer worked with this technique: If we look at the color palette of the awesomeMarker plugin, some colors don't have equivalent in css, like 'lightRed' or 'dardkRed'. So to fit to the color I use in my project, I changed the colors of the gradient so the clusters colors fit perfectly my individuals markers colors.
And as icon-gradient is not supported by firefox and IE, I added a condition to show icon-gradient cluster on chrome, and standard linear-gradient on firefox and IE.
Here is the final piece of code:
var clusters = L.markerClusterGroup({
spiderfyOnMaxZoom: false,
showCoverageOnHover: false,
zoomToBoundsOnClick: true,
iconCreateFunction: function (cluster) {
var markers = cluster.getAllChildMarkers();
var childCount = cluster.getChildCount();
console.log(markers);
var stops = [];
for (let i=0, l=markers.length; i<l; i++) {
var color= markers[i].defaultOptions.icon.options.markerColor;
if (color==="red"){
color="#D13D29";
}else if( color === "orange"){
color="#F69730";
}else if(color === "green"){
color="#6FAC25";
}else if(color === "cadetblue"){
color="#406473";
}else if(color ==="darkred"){
color="#A03336 ";
}else if(color === "beige"){
color="#FFC78C";
}else if(color === "darkgreen"){
color="#708023";
}else if(color === "lightgreen"){
color="#B8F471";
}else if(color === "blue"){
color="#37A7D9 ";
}else if(color === "darkblue"){
color="#0065A0";
}else if(color === "lightblue"){
color="#88DAFF";
}else if(color === "purple"){
color="#CD50B5";
}else if(color === "darkpurple"){
color="#593869";
}else if(color === "pink"){
color="#FF90E8";
}else if(color === "gray"){
color="#575757";
}else if(color === "lightgray"){
color="#A3A3A3";
}
let startPercent = 100 * (i/l);
let endPercent = 100 * (i+1)/l;
stops.push(color + ' ' + startPercent + '%');
stops.push(color + ' ' + endPercent + '%');
}
if(navigator.userAgent.toLowerCase().indexOf('firefox') > -1 || navigator.userAgent.indexOf("MSIE") != -1 || !!document.documentMode == true ){
var html = '<div class="circleMarker" style="background: linear-gradient(to right, ' + stops.join(',') + '" >' + markers.length + "</div>";
return L.divIcon({ html: html, className: "marker-cluster", iconSize: L.point(40, 40) });
}else{
var html = '<div class="circleMarker" style="background: conic-gradient(' + stops.join(',') + '" >' + markers.length + "</div>";
return L.divIcon({ html: html, className: "marker-cluster", iconSize: L.point(40, 40) });
}
},
});
Finaly after testing, the linear gradient doen't work on Ie browser. So I ended up with these condition
var isChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor);
if(isChrome){
var html = '<div class="circleMarker" style="background: conic-gradient(' + stops.join(',') + '" >' + markers.length + '</div>';
return L.divIcon({ html: html, className: "marker-cluster", iconSize: L.point(40, 40) });
}
else if(navigator.userAgent.toLowerCase().indexOf('firefox') > -1 ){
var html = '<div class="circleMarker" style="background: linear-gradient(to right, ' + stops.join(',') + '" >' + markers.length + '</div>';
return L.divIcon({ html: html, className: "marker-cluster", iconSize: L.point(40, 40) });
}else {
var html = '<div class="markerCluster"><span>' + markers.length + '</span></div>';
return L.divIcon({ html: html, className: "marker-cluster" });
}
},
Now if it's chrome, I use icon-gradient, if it's Firefox, linear-gradient, and if it's IE, I draw circles like the original cluster icon.
I didn't find a way to restore the normal cluster icon just for IE browser..