создать пользовательский значок SVG для маркеров листовок

Я использую листовку и маркер.

Я показываю листовки с тысячами маркеров и использую MarkerCluster для создания кластеров. Работает очень хорошо. Теперь я хочу заменить значок, чтобы получить круговые диаграммы как здесь

Поэтому я перегружаю функцию, которая создает значок:

var markerCluster = new L.MarkerClusterGroup({
              showCoverageOnHover: false, spiderfyOnMaxZoom: true, zoomToBoundsOnClick: true,
              iconCreateFunction: defineClusterIcon
           });

Я не могу адаптировать код, это ссылка, потому что я не использую данные geojson, мои маркеры получаются из вызовов ajax. Что я хочу сделать, так это получить простую круговую диаграмму для каждого кластера с 3 частями для «Botanique», «Zoologie» и «Paleontologie». Итак, для кластера я получаю дочерние элементы. для каждого ребенка я могу получить только iconUrl ссылку и посчитать каждую «Ботанику», «Зоологию» и «Палеонтологию».

Заявляю 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;
           }

Есть ли простой способ создать функцию bakeThePie(), возвращающую svg? Все библиотеки, которые я нашел, добавляют svg прямо в div с заданным идентификатором.


person AlainIb    schedule 03.03.2015    source источник


Ответы (1)


рабочий раствор:

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);

И функция defineClusterIcon, которая использует свойство title кластера:

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;

}

Это работает, но не очень хорошо (браузер зависает или отображает всплывающее окно, чтобы остановить скрипт), потому что я делаю итеративные вызовы Ajax, чтобы получить все данные, которые мне нужны. Например, 10 вызовов ajax, каждый из которых создает 500 маркеров. Каждый раз, когда добавляется маркер, кластер маркеров пересчитывается, а также svg для значка, из-за чего браузер зависает. Может есть решение создать иконку svg только при загрузке всех данных или с вызовом функции?

person AlainIb    schedule 27.03.2015