2

As suggested by @TomazicM I post a new question, related to my leaflet issue.

In the search for solutions to a marker display problem, I came across the L.Marker.Stack plugin. I don't know how to use it in my project, I can't find any examples on the net, except those of the author that don't really help me.

I use a geoJson file that lists many hospitals with the same address. Rather than displaying several markers (markerCluster Plugin) containing almost the same informations for the same hospital, the solution of displaying nested markers thanks to L. Marker.Stack seems perfect to me. My goal would be that when I click on a stack of markers, all the information for each marker would be put into an array, so that I could then display them in a div.

Here is my js code

$(document).ready(function() {
    var cartoDb = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
        attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
        subdomains: 'abcd',
        maxZoom: 19
    });
    var cartoDb2 = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
        attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
        subdomains: 'abcd',
        maxZoom: 19
    });

    var map = L.map('map')
        .addLayer(cartoDb)
        .setView([46.85, 2.3518], 6); // LIGNE 14

    var map2 = L.map('map2')
        .addLayer(cartoDb2)
        .setView([46.85, 2.3518], 6); // LIGNE 14

    function onEachFeature(feature, layer) {

        var html = '';
        if (feature.properties.Professeur) {
            html += '<p class="prof">' + feature.properties.Professeur + '</p>';
        }
        if (feature.properties.Professeur2) {
            html += '<p class="prof2">' + feature.properties.Professeur2 + '</p>';
        }
        if (feature.properties.Chu) {
            html += '<p class="chu">' + feature.properties.Chu + '</p>';
        }
        if (feature.properties.Laboratoire) {
            html += '<p class="labo">' + feature.properties.Laboratoire + '</p>';
        }
        if (feature.properties.Prelevement) {
            html += '<p>' + feature.properties.Prelevement + '</p>';
        }
        if (feature.properties.Envoi) {
            html += '<p>' + feature.properties.Envoi + '</p>';
        }
        if (feature.properties.Adresse) {
            html += '<p class="adress">' + feature.properties.Adresse + '</p>';
        }
        if (feature.properties.Cp) {
            html += '<p class="cp">' + feature.properties.Cp + '</p>';
        }

        if (feature.properties.Tel) {
            html += '<p class="tel">' + feature.properties.Tel + '</p>';
        }
        if (feature.properties.Fax) {
            html += '<p class="fax">' + feature.properties.Fax + '</p>';
        }
        if (feature.properties.Mail) {
            html += '<p class="mail"><a href="mailto:' + feature.properties.Mail + '">' + feature.properties.Mail + '</a></p>';
        }
        if (feature.properties.Tel2) {
            html += '<p class="tel">' + feature.properties.Tel2 + '</p>';
        }
        if (feature.properties.Fax2) {
            html += '<p class="fax">' + feature.properties.Fax2 + '</p>';
        }
        if (feature.properties.Mail2) {
            html += '<p class="mail"><a href="mailto:' + feature.properties.Mail2 + '">' + feature.properties.Mail2 + '</a></p>';
        }
        if (feature.properties.Renseignement) {
            html += '<p class="rt">' + feature.properties.Renseignement + '</p>';
        }
        if (feature.properties.Url) {
            html += '<p class="url"><a href="' + feature.properties.Url + '">' + feature.properties.Url + '</a></p>';
        }
        html += '<div class="pictos">';


        if (feature.properties.Examen) {
            html += '<span class="' + feature.properties.Examen + '">' + feature.properties.Examen + '</span>';
        }

        html += '</div>';

        layer.on('click', function() {
            $('#layer_infos .fill').html(html);
            if (L.Browser.mobile) {
                $('#infos').addClass("slide");
                $('#filters').removeClass('slide');
                $('.hamburger').text('Sélectionner un examen').fadeIn();
            }
        })

    } /*here I have a second onEachFeature function  called onEachFeature2 that I use for a second map in a tab */
    var promise = $.getJSON("examen.json");
    promise.then(function(data) {
        var allexamens = L.geoJson(data);
        /*Here I show only 3 examples, but I have 20 code blocks like these !*/
        var ccl18 = L.geoJson(data, {
            filter: function(feature, layer) {
                return feature.properties.Examen == "ccl18";
            },
            onEachFeature: onEachFeature,
            pointToLayer: function(feature, latlng) {

                return L.marker.stack(latlng, {
                    icons: [L.icon.chip({
                        color: '#F69730'
                    }), ],
                    stackOffset: [0, -5]
                });
            }
        })
        var chit1 = L.geoJson(data, {
            filter: function(feature, layer) {
                return feature.properties.Examen == "chit1";
            },
            onEachFeature: onEachFeature,
            pointToLayer: function(feature, latlng) {

                return L.marker.stack(latlng, {
                    icons: [L.icon.chip({
                        color: '#708023'
                    }), ],
                    stackOffset: [0, -5]
                });
            }
        })

        var chitotriosidase = L.geoJson(data, {
            filter: function(feature, layer) {
                return feature.properties.Examen == "chitotriosidase";
            },
            onEachFeature: onEachFeature,
            pointToLayer: function(feature, latlng) {

                return L.marker.stack(latlng, {
                    icons: [L.icon.chip({
                        color: '#593869'
                    }), ],
                    stackOffset: [0, -5]
                });
            }
        })


        $("#ccl18").click(function() {
            if (this.checked) {

                map.addLayer(ccl18);
                map.fitBounds(allexamens.getBounds(), {
                    padding: [50, 50]
                });
            } else {
                map.removeLayer(ccl18);
                map.fitBounds(allexamens.getBounds(), {
                    padding: [50, 50]
                });

            }
        });
        $("#chit1").click(function() {
            if (this.checked) {
                map.addLayer(chit1);
                map.fitBounds(allexamens.getBounds(), {
                    padding: [50, 50]
                });
            } else {
                map.removeLayer(chit1);
                map.fitBounds(allexamens.getBounds(), {
                    padding: [50, 50]
                });
            }
        });
        $("#chitotriosidase").click(function() {
            if (this.checked) {
                map.addLayer(chitotriosidase);

                map.fitBounds(allexamens.getBounds(), {
                    padding: [50, 50]
                });
            } else {
                clusters.removeLayer(chitotriosidase);
                map.fitBounds(allexamens.getBounds(), {
                    padding: [50, 50]
                });

            }
        });

    });


});

With this code, I can display the markers on the map, like this enter image description here

The issue is that I have several markers on the same location, but they are not nested like in the plugin's author example . Here I should have 2 or 3 locations with multiple markers nested.. In addition, the markers are not clickable !

Does someone already used this plugin ??

  • You're creating one stack per GeoJSON point feature. Instead, you should iterate through the features, group together those features with the same point geometry, then create the stacks based on those grouped features. – IvanSanchez Apr 23 at 23:56
  • Thank you very much Ivan for your answer. Yes of course I thought I have to loop instead of duplicating code, but my jquery skills are so poor, I didn't manage to make it work !! That is the only way I found to display them. In addition, I failed trying to make them clickable...But I'll try again !! thanks !! – blogob Apr 24 at 0:14
1

For some reason @IvanSanchez didn't make his plugin interactive, but this can be easily overcome by extending the plugin and adding the interactive part:

L.Marker.MyStack = L.Marker.Stack.extend({
  _initIcon: function () {
    L.Marker.Stack.prototype._initIcon.call(this);
    this._initInteraction();
  }
});

Also icon has to be made interactive by setting its className option to 'leaflet-interactive'

Official plugin example could then look something like this:

L.Marker.MyStack = L.Marker.Stack.extend({
  _initIcon: function () {
    L.Marker.Stack.prototype._initIcon.call(this);
    this._initInteraction();
  }
});

var myCenter = new L.LatLng(63.41, 10.41);
var map = new L.Map('map', {center: myCenter, zoom: 6});

var positron = L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, &copy; <a href="http://cartodb.com/attributions">CartoDB</a>'
}).addTo(map);

var points = [[59.9274956808828,10.733642578125],[59.23217626921806,9.1240234375],[59.66774058164963,9.64599609375],[58.983991031797785,5.767822265625],[61.24381719465578,7.09716796875],[61.13262899079795,10.458984375],[60.62471311568258,6.427001953125],[60.97843744941454,9.239501953125],[60.38671955355991,5.306396484375],[61.454521127671924,5.811767578125],[62.46664555258511,6.141357421875],[63.104699747121096,7.75634765625],[62.580695541118914,11.315917968749998],[61.83282044219323,8.5418701171875],[63.470144746565445,10.87646484375]]
var colors = [ '#005777', '#37A4AB', '#B2EEE6', '#5C308C', '#A640A2', '#E76CAC', '#FFC2C7'];

points.forEach(function(point) {
  var chipIcons = [];
  var rdColors = getRandomOrderedColors();
  for (var i = 0; i < rdColors.length; i++) {
    chipIcons.push(L.icon.chip({
      color: rdColors[i],
      className: 'leaflet-interactive'
    }));
  }
  var stack = new L.Marker.MyStack(point, {
    icons: chipIcons,
    stackOffset: [0, -5]
  });

  stack.on('click', function(evt) {
    console.log('Marker clicked!');
  });

  map.addLayer(stack);
})

function getRandomOrderedColors() {
  var numColors = 3 + Math.floor(Math.random() * 17);
  var rdColors = [];
  for (var i = 0; i < numColors; i++) {
    var rdIndex = Math.floor(Math.random()*colors.length);
    rdColors.push({
      color: colors[rdIndex],
      index: rdIndex
    });
  }
  rdColors.sort(function(a, b) {
    return (a.index < b.index) ? 1 : -1;
  });
  return rdColors.map(function(c) {
    return c.color;
  });
}
| improve this answer | |
  • Thank you very much TomazicM for your contribution, I'll save your code for later, thank you! – blogob Apr 24 at 7:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.