Leaflet.js Marker Clustering — Grouping Points at Scale
In this tutorial, you will learn about Leaflet.js Marker Clustering. We cover key concepts, practical examples, and best practices to help you master this topic.
Leaflet.js marker clustering groups nearby markers into clusters that expand as users zoom in, enabling performant display of thousands of points.
What You'll Learn
By the end of this guide, you will install and configure Leaflet.markercluster, customize cluster appearance, set clustering distance and bounds, handle cluster click events, and render 10,000+ points smoothly.
Basic Clustering
// npm install leaflet.markercluster
var markers = L.markerClusterGroup();
for (var i = 0; i < 1000; i++) {
var marker = L.marker([
40 + Math.random() * 5,
-100 + Math.random() * 10
]);
markers.addLayer(marker);
}
map.addLayer(markers);
Custom Cluster Icons
var markers = L.markerClusterGroup({
iconCreateFunction: function(cluster) {
var count = cluster.getChildCount();
var size = count < 10 ? 'small' : count < 100 ? 'medium' : 'large';
return L.divIcon({
html: '<span>' + count + '</span>',
className: 'cluster cluster-' + size,
iconSize: L.point(40, 40)
});
}
});
Spiderfier Configuration
var markers = L.markerClusterGroup({
spiderfyOnMaxZoom: true,
showCoverageOnHover: false,
zoomToBoundsOnClick: true,
maxClusterRadius: 80,
disableClusteringAtZoom: 16
});
Common Mistakes
1. Not Importing CSS
markercluster requires its CSS file. Missing CSS causes invisible or malformed clusters.
2. Clustering Too Few Markers
If maxClusterRadius is too large, distant markers cluster together misleadingly.
3. Spiderfier on Dense Clusters
With disableClusteringAtZoom too high, thousands of markers render individually. Set it judiciously.
4. Not Using chunkedLoading
For 50,000+ markers, use chunkedLoading: true to add layers in batches via requestAnimationFrame.
5. Cluster Click Propagation
Clicking a cluster zooms by default. Stop propagation if you need custom click behavior.
Practice Questions
Q1: What library provides clustering for Leaflet? A: Leaflet.markercluster.
Q2: How does maxClusterRadius work? A: It sets the maximum distance in pixels for markers to be grouped into one cluster.
Q3: What is spiderfier? A: When zooming into a cluster at max zoom, markers expand into a spiral arrangement to avoid overlap.
Q4: How do you customize cluster icons? A: Use iconCreateFunction on the markerClusterGroup options.
Q5: How many markers can markercluster handle? A: Up to 100,000 with chunkedLoading. Beyond that, use canvas-based rendering.
Challenge: Build a map with 5,000 randomly placed markers. Add a search box that zooms to the cluster containing the matching marker.
FAQ
Try It Yourself
Build a map with random points and custom clusters.
<!DOCTYPE html>
<html>
<head>
<title>Clustering Demo</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9/dist/leaflet.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.5/dist/MarkerCluster.css" />
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.5/dist/MarkerCluster.Default.css" />
<script src="https://unpkg.com/leaflet@1.9/dist/leaflet.js"></script>
<script src="https://unpkg.com/leaflet.markercluster@1.5/dist/leaflet.markercluster.js"></script>
<style>.cluster-small { background-color: #4ecdc4; border-radius: 50%; color: #fff; display: flex; align-items: center; justify-content: center; font-weight: bold; } .cluster-medium { background-color: #ff6b35; border-radius: 50%; color: #fff; display: flex; align-items: center; justify-content: center; font-weight: bold; } .cluster-large { background-color: #e74c3c; border-radius: 50%; color: #fff; display: flex; align-items: center; justify-content: center; font-weight: bold; }</style>
</head>
<body style="font-family:sans-serif;padding:20px;">
<h2>Marker Clustering</h2>
<div id="map" style="height:400px;border-radius:8px;"></div>
<script>
var map = L.map('map').setView([42, -95], 5);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OSM'
}).addTo(map);
var markers = L.markerClusterGroup({
iconCreateFunction: function(cluster) {
var count = cluster.getChildCount();
var size = count < 10 ? '30px' : count < 50 ? '40px' : '48px';
var cls = count < 10 ? 'cluster-small' : count < 50 ? 'cluster-medium' : 'cluster-large';
return L.divIcon({
html: '<span>' + count + '</span>',
className: cls,
iconSize: L.point(size.replace('px',''), size.replace('px',''))
});
},
maxClusterRadius: 60
});
for (var i = 0; i < 500; i++) {
var lat = 35 + Math.random() * 14;
var lng = -105 + Math.random() * 20;
var marker = L.marker([lat, lng]);
marker.bindPopup('Point ' + i + '<br>Lat: ' + lat.toFixed(3) + ', Lng: ' + lng.toFixed(3));
markers.addLayer(marker);
}
map.addLayer(markers);
</script>
</body>
</html>
What's Next
Create heatmap layers.
Heatmap — Heatmap visualization. Routing — Routing and directions.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro