Reputation: 4728
I'm using leaflet and markercluster.
I display on a leaflet map with thousands of markers and I use MarkerCluster to create clusters. It's work very good. Now i want to replace the icon to get pie charts as the example here
So I overload the function which creates the icon:
var markerCluster = new L.MarkerClusterGroup({
showCoverageOnHover: false, spiderfyOnMaxZoom: true, zoomToBoundsOnClick: true,
iconCreateFunction: defineClusterIcon
});
I can't adapt the code is the link because i don't use geojson data, my markers are get from ajax calls.
What i want to do is to get a simple pie chart for each clusters with 3 parts for 'Botanique', 'Zoologie' and 'Paleontologie'.
So for a cluster i get the childs. for each child I only can get the iconUrl
link and count each 'Botanique', 'Zoologie' and 'Paleontologie'.
I declare the iconCreateFunction()
:
function defineClusterIcon(cluster) {
var children = cluster.getAllChildMarkers();
var bcount = 0,
zcount = 0,
pcount = 0 ;
for(var i in children){
var child = children[i];
switch ( child.options.icon.options.iconUrl ){
case 'resources/vendors/leaflet/images/marker-icon-bota.png' :
hcount ++; break ;
case 'resources/vendors/leaflet/images/marker-icon-paleon.png' :
pcount ++; break ;
case 'resources/vendors/leaflet/images/marker-icon-zoo.png' :
zcount ++; break ;
}
}
var data = {
'Botanique' : hcount ,
'Zoologie' : zcount ,
'Paleontologie' : pcount
};
//bake some svg markup
var html = bakeThePie(data);
//Create a new divIcon and assign the svg markup to the html property
myIcon = new L.DivIcon({
html: html,
className: 'marker-cluster',
iconSize: new L.Point(iconDim, iconDim)
});
return myIcon;
}
Is there a simple way to create the bakeThePie()
function who return an svg ?
All the library I found append the svg directly in a div with a given id.
Upvotes: 1
Views: 3262
Reputation: 4728
working solution :
var markerCluster = new L.MarkerClusterGroup({
showCoverageOnHover: false,
spiderfyOnMaxZoom: true,
zoomToBoundsOnClick: true,
iconCreateFunction: defineClusterIcon // this function render the cluster icon
});
the way markers are created :
L.marker([DECIMALLATITUDE, L_DECIMALLONGITUDE],{icon: icontmp, 'title': domaine,'domaine':domaine,'occurenceid':id}).on('click', getSpecimenDataOnClick).addTo(markerCluster);
And the defineClusterIcon function who use the title property of the cluster:
function defineClusterIcon(cluster) {
/*function that generates a svg markup for the pie chart*/
function bakeThePie(options) {
/*data and valueFunc are required*/
if (!options.data || !options.valueFunc) {
return '';
}
var data = options.data,
valueFunc = options.valueFunc,
r = options.outerRadius ? options.outerRadius : 28, //Default outer radius = 28px
rInner = options.innerRadius ? options.innerRadius : r - 10, //Default inner radius = r-10
strokeWidth = options.strokeWidth ? options.strokeWidth : 1, //Default stroke is 1
pathClassFunc = options.pathClassFunc ? options.pathClassFunc : function () {
return '';
}, //Class for each path
pathTitleFunc = options.pathTitleFunc ? options.pathTitleFunc : function () {
return '';
}, //Title for each path
pieClass = options.pieClass ? options.pieClass : 'marker-cluster-pie', //Class for the whole pie
pieLabel = options.pieLabel ? options.pieLabel : d3.sum(data, valueFunc), //Label for the whole pie
pieLabelClass = options.pieLabelClass ? options.pieLabelClass : 'marker-cluster-pie-label', //Class for the pie label
origo = (r + strokeWidth), //Center coordinate
w = origo * 2, //width and height of the svg element
h = w,
donut = d3.layout.pie(),
arc = d3.svg.arc().innerRadius(rInner).outerRadius(r);
//Create an svg element
var svg = document.createElementNS(d3.ns.prefix.svg, 'svg');
//Create the pie chart
var vis = d3.select(svg)
.data([data])
.attr('class', pieClass)
.attr('width', w)
.attr('height', h);
var arcs = vis.selectAll('g.arc')
.data(donut.value(valueFunc))
.enter().append('svg:g')
.attr('class', 'arc')
.attr('transform', 'translate(' + origo + ',' + origo + ')');
arcs.append('svg:path')
.attr('class', pathClassFunc)
.attr('stroke-width', strokeWidth)
.attr('d', arc)
.append('svg:title')
.text(pathTitleFunc);
vis.append('text')
.attr('x', origo)
.attr('y', origo)
.attr('class', pieLabelClass)
.attr('text-anchor', 'middle')
//.attr('dominant-baseline', 'central')
/*IE doesn't seem to support dominant-baseline, but setting dy to .3em does the trick*/
.attr('dy', '.3em')
.text(pieLabel);
//Return the svg-markup rather than the actual element
return serializeXmlNode(svg);
}
/*Helper function*/
function serializeXmlNode(xmlNode) {
if (typeof window.XMLSerializer != "undefined") {
return (new window.XMLSerializer()).serializeToString(xmlNode);
} else if (typeof xmlNode.xml != "undefined") {
return xmlNode.xml;
}
return "";
}
var children = cluster.getAllChildMarkers();
var n = children.length; //Get number of markers in cluster
var strokeWidth = 1; //Set clusterpie stroke width
var r = 30 - 2 * strokeWidth - (n < 10 ? 12 : n < 100 ? 8 : n < 1000 ? 4 : 0); //Calculate clusterpie radius...
var iconDim = (r + strokeWidth) * 2; //...and divIcon dimensions (leaflet really want to know the size)
var data = d3.nest() //Build a dataset for the pie chart
.key(function (d) {
return d.options.title;
})
.entries(children, d3.map);
//bake some svg markup
var html = bakeThePie({
data : data,
valueFunc : function (d) {
return d.values.length;
},
strokeWidth : 1,
outerRadius : r,
innerRadius : r - 10,
pieClass : 'cluster-pie',
pieLabel : n,
pieLabelClass : 'marker-cluster-pie-label',
pathClassFunc : function (d) {
return "category-" + d.data.key;
},
pathTitleFunc : function (d) {
return d.data.key + ' (' + d.data.values.length + ' specimen' + (d.data.values.length != 1 ? 's' : '') + ')';
}
});
//Create a new divIcon and assign the svg markup to the html property
var myIcon = new L.DivIcon({
html : html,
className : 'marker-cluster',
iconSize : new L.Point(iconDim, iconDim)
});
return myIcon;
}
This work but not so good (the browser freeze or display a popup to stop the script) because I make iteratives Ajax calls to get all the data I need. For exemple 10 ajax calls who creates each one 500 markers. Each time a marker is added the marker cluster are recalculated and the svg for the icon too who make the browser freeze. Maybe there is a solution to create the svg icon only when all the data is loaded or with a function call ?
Upvotes: 0