Displaying a large number of points on a map, keeping it clear and usable is a hard job, especially at higher level where identifying each feature is quite impossible.
Marker clustering is a technique where individual points are grouped into clusters according to a specific algorithm based on the radius of clusters. Grouped points are represented on the map by a marker, the cluster symbol, with the number of points included in it. Clustering eliminates overlapping points and makes the web map clearer.
Here is an image that shows how your web mapping application will look like implementing this representation method.
When zooming in, the clusters shrink, and individual points are displayed when distance exceed radius parameter.
Check this live example which displays all the pubs across the UK ~ 22.000 pubs :
This sample implements the popular Supercluster library which uses the k-d trees data structure for spatial indexing. Having an index for each zoom allows to instantly query clusters for any map view and ensure smooth transitions between zoom levels.
Supercluster works pretty well for Woosmap Map JS. The library expect location data to be in the form of an array of GeoJSON Feature objects. Each feature’s geometry
must be a GeoJSON Point.
First step is to load your GeoJSON file and build the spatial index as below:
fetch("https://demo.woosmap.com/misc/data/uk-all-pubs.geojson")
.then((response) => response.json())
.then((data) => {
const geojsonFeatures = data["features"];
index = new Supercluster({
radius: 40,
extent: 256,
maxZoom: 14,
minPoints: 5
}).load(geojsonFeatures);
});
Processing points is done only once. Clusters are computed for each zoom (between minZoom
and maxZoom
parameters).
To highlight processing time, you can pass log: true
parameter to Supercluster constructor. For this sample, whole index is built in less than 50ms. Blazing fast!
prepare 22169 points: 1.5ms
z14: 19530 clusters in 18ms
z13: 16822 clusters in 10ms
z12: 14141 clusters in 6ms
z11: 11050 clusters in 4ms
z10: 7121 clusters in 3ms
z9: 3101 clusters in 2ms
z8: 1020 clusters in 0ms
z7: 277 clusters in 0ms
z6: 86 clusters in 0ms
z5: 27 clusters in 0ms
z4: 9 clusters in 0ms
z3: 2 clusters in 0ms
z2: 1 clusters in 0ms
z1: 1 clusters in 0ms
z0: 1 clusters in 0ms
total time: 44.5ms
Once built, clusters’ index can be displayed as a marker, labeled with the number of locations. Here the marker is a circle which radius and color vary depending on the cluster size.
const clusterData = index.getClusters(bbox, map.getZoom());
const markers = clusterData.map((feature) => {
return createClusterIcon(feature)
});
function createClusterIcon(feature) {
const count = feature.properties.point_count;
const color = count < 80 ? "#0B9D58" : count < 500 ? "#F5B300" : "#DA0A40";
const size = count < 80 ? 45 : count < 400 ? 55 : 65;
const svg = window.btoa(`
<svg fill="${color}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240">
<circle cx="120" cy="120" opacity=".2" r="110" />
</svg>`);
const marker = new woosmap.map.Marker({
labelOrigin: new woosmap.map.Point(13, 15),
label: {
text: feature.properties.point_count_abbreviated,
color: "white"
},
position: latlng,
icon: {
url: `data:image/svg+xml;base64,${svg}`,
scaledSize: new window.woosmap.map.Size(size, size)
},
map: map
});
return marker;
}
We’re looking forward to seeing cool clustering implementation with Woosmap Map from you! If you have any questions or comments don’t hesitate to react in this thread.