Leaflet 创建自定义传单标记群集svg图标

Leaflet 创建自定义传单标记群集svg图标,leaflet,markerclusterer,Leaflet,Markerclusterer,我用传单和markercluster 我在传单地图上显示数千个标记,并使用MarkerCluster创建簇。这工作做得很好。现在我想替换图标以获得饼图 因此,我重载了创建图标的函数: var markerCluster = new L.MarkerClusterGroup({ showCoverageOnHover: false, spiderfyOnMaxZoom: true, zoomToBoundsOnClick: true, ico

我用传单和markercluster

我在传单地图上显示数千个标记,并使用MarkerCluster创建簇。这工作做得很好。现在我想替换图标以获得饼图

因此,我重载了创建图标的函数:

var markerCluster = new L.MarkerClusterGroup({
              showCoverageOnHover: false, spiderfyOnMaxZoom: true, zoomToBoundsOnClick: true,
              iconCreateFunction: defineClusterIcon
           });
我无法修改链接的代码,因为我不使用geojson数据,我的标记来自ajax调用。 我想做的是为每个簇得到一个简单的饼图,其中包含“植物学”、“动物学”和“古生物学”三个部分。 所以对于集群,我得到了childs。对于每个孩子,我只能获得iconUrl链接,并计算每个“植物学”、“动物学”和“古生物学”

我声明
iconCreateFunction()

有没有一种简单的方法来创建返回svg的
bakeThePie()
函数? 我找到的所有库都将svg直接附加到具有给定id的div中。

工作解决方案:

var markerCluster = new L.MarkerClusterGroup({
              showCoverageOnHover: false,
              spiderfyOnMaxZoom: true,
              zoomToBoundsOnClick: true,
              iconCreateFunction: defineClusterIcon // this function render the cluster icon 
           });
创建标记的方式:

 L.marker([DECIMALLATITUDE, L_DECIMALLONGITUDE],{icon: icontmp, 'title': domaine,'domaine':domaine,'occurenceid':id}).on('click', getSpecimenDataOnClick).addTo(markerCluster);
以及使用群集的title属性的defineClusterIcon函数:

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;
函数定义集群(集群){
/*函数,用于为饼图生成svg标记*/
函数烘焙(选项){
/*数据和valueFunc是必需的*/
如果(!options.data | |!options.valueFunc){
返回“”;
}
var data=options.data,
valueFunc=options.valueFunc,
r=options.outerRadius?options.outerRadius:28,//默认外半径=28px
rInner=options.innerRadius?options.innerRadius:r-10,//默认内半径=r-10
strokeWidth=options.strokeWidth?options.strokeWidth:1,//默认笔划为1
pathClassFunc=options.pathClassFunc?options.pathClassFunc:函数(){
返回“”;
},//每个路径的类
pathTitleFunc=options.pathTitleFunc?options.pathTitleFunc:函数(){
返回“”;
},//每个路径的标题
pieClass=options.pieClass?options.pieClass:'标记群集饼图',//整个饼图的类
pieLabel=options.pieLabel?options.pieLabel:d3.sum(data,valueFunc),//整个饼图的标签
PielLabelClass=options.PielLabelClass?options.PielLabelClass:'标记簇饼图标签',//饼图标签的类
origo=(r+strokeWidth),//中心坐标
w=origo*2,//svg元素的宽度和高度
h=w,
donut=d3.layout.pie(),
arc=d3.svg.arc().innerRadius(rInner).outerRadius(r);
//创建一个svg元素
var svg=document.createElements(d3.ns.prefix.svg,'svg');
//创建饼图
var vis=d3.选择(svg)
.数据([数据])
.attr('class',pieClass)
.attr('宽度',w)
.attr('高度',h);
var arcs=vis.selectAll('g.arc')
.data(圆环值(valueFunc))
.enter().append('svg:g')
.attr('class','arc')
.attr('transform','translate('+origo+','+origo+'));
append('svg:path')
.attr('class',pathClassFunc)
.attr('stroke-width',strokeWidth)
.attr('d',弧)
.append('svg:title')
.text(路径标题函数);
vis.append('text')
.attr('x',origo)
.attr('y',origo)
.attr('class',pieLabelClass)
.attr('text-anchor','middle')
//.attr('主基线','中心')
/*IE似乎不支持主导基线,但将dy设置为.3em就可以了*/
.attr('dy','.3em'))
.文本(标签);
//返回svg标记,而不是实际的元素
返回XML节点(svg);
}
/*辅助函数*/
函数序列化xmlNode(xmlNode){
if(typeof window.XMLSerializer!=“未定义”){
return(new window.XMLSerializer()).serializeToString(xmlNode);
}else if(typeof xmlNode.xml!=“未定义”){
返回xmlNode.xml;
}
返回“”;
}
var children=cluster.getAllChildMarkers();
var n=childrence.length;//获取集群中的标记数
var strokeWidth=1;//设置clusterpie笔划宽度
var r=30-2*冲程宽度-(n<10?12:n<100?8:n<1000?4:0);//计算群集半径。。。
var iconDim=(r+strokeWidth)*2;/…和divIcon尺寸(传单确实想知道尺寸)
var data=d3.nest()//为饼图构建数据集
.键(功能(d){
返回d.options.title;
})
.条目(儿童、d3.地图);
//烘焙一些svg标记
var html=bakethespie({
数据:数据,
valueFunc:函数(d){
返回d.value.length;
},
冲程宽度:1,
外层:r,
内半径:r-10,
pieClass:'簇派',
皮恩,
PielLabelClass:“标记簇饼图标签”,
pathClassFunc:函数(d){
返回“category-”+d.data.key;
},
路径标题函数:函数(d){
返回d.data.key+'('+d.data.values.length+'sample'+(d.data.values.length!=1?'s':'');
}
});
//创建一个新的divIcon并将svg标记分配给html属性
var myIcon=新的L.DivIcon({
html:html,
类名:“标记群集”,
iconSize:新的L.Point(iconDim,iconDim)
});
返回myIcon;
}

这是可行的,但不是很好(浏览器冻结或显示一个弹出窗口来停止脚本),因为我使用迭代Ajax调用来获取所需的所有数据。例如,10个ajax调用,每个调用创建500个标记。每次添加标记时,都会重新计算标记簇,并且图标的svg也会使浏览器冻结。 也许有一种解决方案可以仅在加载所有数据或使用函数调用时创建svg图标

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;