Fast marker clustering for Google Maps supporting hundreds of thousands of markers. A solution to 'too many markers'.
Clusters LatLng points to allow a map to display different numbers of markers at different zoom levels. Built with the fast retrieval of hundreds of thousands of Google Maps markers in mind.
Originally developed for a personal project TheyHaveYour.Info which required a clusterer for Google Maps capable of fast browsing and aggregation of 200,000+ map markers.
No production dependencies required.
Even if it takes a few seconds to actually cluster 200000 markers, once it's done you can zoom the map it doesn't need to recalculate (unlike MarkerClusterer in google-maps-utility-library-v3) - browsing the map with ClusterFlag is fast! This greedy clustering algorithm is heavily based on the wonderful Leaflet.markercluster (MIT License).
Include the javascript file which will set the global variable ClusterFlag
.
Including the script within an IIFE will make the variable non-global.
Include your mapping library and then import the LatLng
and LatLngBounds
classes into ClusterFlag, e.g.
ClusterFlag.setImports(google.maps.LatLng, google.maps.LatLngBounds);
The LatLng class must have lat()
and lng()
methods and constructor LatLng(lat, lng)
.
The LatLngBounds class must have constructor LatLngBounds(NE, SW)
and methods getSouthWest()
, getNorthEast()
, contains(latlng)
, intersects(bounds)
, extend(latlng)
and union(bounds)
If you aren't using Google Maps or a mapping library, you can use the MapLatLng
and MapBounds
classes included in the test folder.
To create the clusterer use var cf = new ClusterFlag.Clusterer(maxZoom, clusterWidth)
where:
get
method shouldn't suffer.Each marker added to the clusterer can have any properties, but must always have:
To add a marker cf.add(marker)
When everything has been added you can call cf.finish()
to clean up temporary arrays which are only required if adding more items and to calculate aggregate properties such as child count and centre of mass.
On map events such as zooming or dragging, call cf.get(map.getBounds() : LatLngBounds, zoomLevel)
to return an array containing marker objects (the same as you added to the clusterer) and Cluster objects. Actually displaying the results on the map is your problem although a basic example app is included!
A cluster object has the following properties populated:
cf.top
) has zoom = -1 and parent = nullCalculate aggregate properties of clusters using accumulate(acc, marker, cluster, finish)
as seen in Cluster.js.
Used in Cluster.recalculateBounds
to calculate and attach the bounds
, count
and centreOfMass
properties of clusters.
Example to calculate the number of blue and green markers and to attach the result to each cluster object:
cf.accumulate(function() {
return {
blue: 0, green: 0
}
}, function(accum, marker) {
//Our markers will of course need to have a color property
if (marker.color === 'blue')
accum.blue++
else if(marker.color === 'green')
accum.green++
}, function(accum, childCluster) {
accum.blue += childCluster.blueDescendants
accum.green += childCluster.greenDescendants
}, function(self, accum) {
//Every cluster will now have the following properties
self.blueDescendants = accum.blue
self.greenDescendants = accum.green
self.overallColor = accum.blue >= accum.green ? 'blue' : 'green';
})
Copyright 2014 Benjamin Caller
ClusterFlag is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
ClusterFlag is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with ClusterFlag. If not, see http://www.gnu.org/licenses/.
For alternative licensing please contact me. Also it'd be nice to know if you make use of this library in a project.