From your above additional code, it looks like you are loading Leaflet.markercluster script before Leaflet script:
<script src="leaflet.markercluster-src.js">
<script src="http://code.jquery.com/jquery-1.12.0.min.js">
<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js">
You should rather load it after:
<script src="http://code.jquery.com/jquery-1.12.0.min.js">
<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js">
<script src="leaflet.markercluster-src.js">
You should learn to use your browser console (on Windows / Linux browsers, press F12; on Mac OS browsers, press Command ⌘+Option ⌥+i) to look for potential errors.
In your case, I suspect there should be something like "ReferenceError: L is not defined
" due to Leaflet.markercluster trying to attach some code to Leaflet's L
namespace, but could not find it because it is not loaded yet.
As suggested by TomazicM, there might be a simplier way to achieve this, with much more cleaner code! Here I'm duplicating a bunch of code, because for the moment I don't know how to simplify it. But it works !
I also managed to remove duplicate properties from a geoJSON file here.
I give here all my js code. It might help other newbies like me, and of course, if there are some advanced coders who want to improve it, you're welcome.
@TomazicM, again thank you very very much for all your help. Thanks to you I can improve my skill little by litte !! : )
Here is my code :
$(document).ready(function(){
var cartoDb = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>',
subdomains: 'abcd',
maxZoom: 18
});
var cartoDb2 = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>',
subdomains: 'abcd',
maxZoom: 18
});
/* Here is an example of how I define my custom icons . I'm using leaflet.awesome-markers */
var ccl18Icon = L.AwesomeMarkers.icon({
prefix: 'fa', //font awesome rather than bootstrap
iconColor: 'white',
markerColor: 'orange', // see colors above
icon: 'ambulance' //http://fortawesome.github.io/Font-Awesome/icons/
});
Then a function for each markers, similar to an info window, but I put it in a dynamic panel outside the map with : $('#layer_infos .fill').html(html);
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();
}
})
}
I'm duplicating this last part for my second map in tab 2. Then I create my cluster groups
var promise = $.getJSON("examen.json");
/*cluster for the first map */
var clusters = L.markerClusterGroup({
spiderfyOnMaxZoom: false,
showCoverageOnHover: false,
zoomToBoundsOnClick: true
});
Here is my cluster click action with associated html. I'm targetting the markers inside the selected cluster only. I'm also duplicating this code for my second map !
clusters.on('clusterclick', function(a){
if(a.layer._zoom == 18){
var html = '';
for (feat in a.layer._markers){
if (a.layer._markers[feat].feature.properties['Professeur']) {
html += '<p class="prof">' + a.layer._markers[feat].feature.properties['Professeur'] + '</p>';
}
if (a.layer._markers[feat].feature.properties['Professeur2']) {
html += '<p class="prof2">' + a.layer._markers[feat].feature.properties['Professeur2'] + '</p>';
}
if (a.layer._markers[feat].feature.properties['Chu']) {
html += '<p class="chu">' + a.layer._markers[feat].feature.properties['Chu'] + '</p>';
}
if (a.layer._markers[feat].feature.properties['Laboratoire']) {
html += '<p class="labo">' + a.layer._markers[feat].feature.properties['Laboratoire'] + '</p>';
}
if (a.layer._markers[feat].feature.properties['Prelevement']) {
html += '<p>' + a.layer._markers[feat].feature.properties['Prelevement'] + '</p>';
}
if (a.layer._markers[feat].feature.properties['Envoi']) {
html += '<p>' + a.layer._markers[feat].feature.properties['Envoi'] + '</p>';
}
if (a.layer._markers[feat].feature.properties['Adresse']) {
html += '<p class="adress">' + a.layer._markers[feat].feature.properties['Adresse'] + '</p>';
}
if (a.layer._markers[feat].feature.properties['Cp']) {
html += '<p class="cp">' + a.layer._markers[feat].feature.properties['Cp'] + '</p>';
}
if (a.layer._markers[feat].feature.properties['Tel']) {
html += '<p class="tel">' + a.layer._markers[feat].feature.properties['Tel'] + '</p>';
}
if (a.layer._markers[feat].feature.properties['Fax']) {
html += '<p class="fax">' + a.layer._markers[feat].feature.properties['Fax'] + '</p>';
}
if (a.layer._markers[feat].feature.properties['Mail']) {
html += '<p class="mail"><a href="mailto:' + a.layer._markers[feat].feature.properties['Mail'] +'">' + a.layer._markers[feat].feature.properties['Mail'] + '</a></p>';
}
if (a.layer._markers[feat].feature.properties['Tel2']) {
html += '<p class="tel">' + a.layer._markers[feat].feature.properties['Tel2'] + '</p>';
}
if (a.layer._markers[feat].feature.properties['Fax2']) {
html += '<p class="fax">' + a.layer._markers[feat].feature.properties['Fax2'] + '</p>';
}
if (a.layer._markers[feat].feature.properties['Mail2']) {
html += '<p class="mail"><a href="mailto:' + a.layer._markers[feat].feature.properties['Mail2'] +'">' + a.layer._markers[feat].feature.properties['Mail2'] + '</a></p>';
}
if (a.layer._markers[feat].feature.properties['Renseignement']) {
html += '<p class="rt">' + a.layer._markers[feat].feature.properties['Renseignement'] + '</p>';
}
if (a.layer._markers[feat].feature.properties['Url']) {
html += '<p class="url"><a href="' + a.layer._markers[feat].feature.properties['Url'] + '">' + a.layer._markers[feat].feature.properties['Url'] + '</a></p>';
}
html+='<div class="pictos">';
if (a.layer._markers[feat].feature.properties['Examen']) {
html += '<span class="' + a.layer._markers[feat].feature.properties['Examen'] + '">' + a.layer._markers[feat].feature.properties['Examen'] + '</span>';
}
html+='</div>';
}
$('#layer_infos .fill').html(html);
}
})
Then, here an example of how I get geoJson data
promise.then(function(data) {
var allexamens = L.geoJson(data);
/* related filters and makers */
var ccl18 = L.geoJson(data, {
filter: function(feature, layer) {
return feature.properties.Examen == "ccl18";
},
onEachFeature: onEachFeature,
pointToLayer: function(feature, latlng) {
return L.marker(latlng, {
icon: ccl18Icon
})
}
})
And here is an example of my click action on filters
$("#ccl18").click(function() {
if (this.checked) {
ccl18.addTo(clusters);
map.fitBounds(allexamens.getBounds(), {
padding: [50, 50]
});
} else {
clusters.removeLayer(ccl18);
map.fitBounds(allexamens.getBounds(), {
padding: [50, 50]
});
}
});
Thenn I close my "promise.then(function(data) {"
});
And At the end I call my clusters, and close my $(document).ready(function(){..
clusters.addTo(map);
clusterade.addTo(map2);
});
With all this code, I have my map working as expected. Single markers, and clusters.
So before I had this :
And now, When I click on clusters, instead of having separated markers, I get the data of the markers contained in "this" cluster only, and display it in a pannel
Best Answer
You are creating new marker pair at each call of the function, so old markers stay where they are. Instead you should create new marker pair only once and at later calls just change their attributes.
Your function could then look something like this: