{"id":15304567,"url":"https://github.com/monkeymars/prunecluster","last_synced_at":"2025-10-08T09:30:46.034Z","repository":{"id":149889782,"uuid":"46058248","full_name":"monkeymars/PruneCluster","owner":"monkeymars","description":"Fast and realtime marker clustering","archived":false,"fork":true,"pushed_at":"2015-10-12T13:02:31.000Z","size":1568,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-02T07:56:58.365Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"SINTEF-9012/PruneCluster","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/monkeymars.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-11-12T14:30:00.000Z","updated_at":"2015-11-12T14:30:01.000Z","dependencies_parsed_at":"2023-04-09T18:43:19.704Z","dependency_job_id":null,"html_url":"https://github.com/monkeymars/PruneCluster","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monkeymars%2FPruneCluster","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monkeymars%2FPruneCluster/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monkeymars%2FPruneCluster/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monkeymars%2FPruneCluster/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/monkeymars","download_url":"https://codeload.github.com/monkeymars/PruneCluster/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235700110,"owners_count":19031668,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-01T07:57:00.920Z","updated_at":"2025-10-08T09:30:45.476Z","avatar_url":"https://github.com/monkeymars.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![PruneCluster](http://medias.master-bridge.eu/e30525b1a92f01204ac69039a642e370c85bf906.png)\n============\n\nPruneCluster is a fast and realtime marker clustering library.\n\nIt's working with [Leaflet](http://leafletjs.com/) as an alternative to [Leaflet.markercluster](https://github.com/Leaflet/Leaflet.markercluster).\n\n \n*The library is designed for large datasets or live situations.* The memory consumption is kept low and the library is fast on mobile devices, thanks to a new algorithm inspired by collision detection in physical engines.\n\n![](http://medias.master-bridge.eu/resize/728/720/59dedba492400bfefddf3179fa83f18fbf4ee599.png)\n**Some tweets over the world**\n\n### Features\n\n#### Realtime\nThe clusters can be updated in realtime. It's perfect for live situations.\n\n#### Fast\n\nNumber of markers|First step|Update (low zoom level)|Update (high zoom level)\n---------|------------------|------------------------|------------------\n[100](http://sintef-9012.github.io/PruneCluster/examples/random.100.html)|instant|instant|instant\n[1 000](http://sintef-9012.github.io/PruneCluster/examples/random.1000.html)|instant|instant|instant\n[10 000](http://sintef-9012.github.io/PruneCluster/examples/random.10000.html)|14ms|3ms|2ms\n[60 000](http://sintef-9012.github.io/PruneCluster/examples/random.60000.html)|70ms|23ms|9ms\n[150 000](http://sintef-9012.github.io/PruneCluster/examples/random.150000.html)|220ms|60ms|20ms\n[1 000 000](http://sintef-9012.github.io/PruneCluster/examples/random.1000000.html)|1.9s|400ms|135ms\n\nThese values are tested with random positions, on a recent laptop, using Chrome 38. One half of markers is moving randomly and the other half is static. It is also fast enough for mobile devices.\n\nIf you prefer real world data, the [50k Leaflet.markercluster example](http://sintef-9012.github.io/PruneCluster/examples/realworld.50000.html) is computed in 60ms *([original](http://sintef-9012.github.io/Leaflet.markercluster/example/marker-clustering-realworld.50000.html))*.\n\n#### Weight\nYou can specify the weight of each marker.\n\nFor example, you may want to add more importance to a marker representing an incident, than a marker representing a tweet.\n\n#### Categories\n\nYou can specify a category for the markers. Then a small object representing the number of markers for each category is attached to the clusters. This way, you can create cluster icons adapted to their content.\n\n[![](http://medias.master-bridge.eu/ebc9e5393a8a018abb8771a3155b802f05995792.png)](http://sintef-9012.github.io/PruneCluster/examples/random.10000-categories.html) [![](http://medias.master-bridge.eu/d02e09d5fe43654141693f22924f606f4fd6960a.png)](http://sintef-9012.github.io/PruneCluster/examples/random.10000-categories-2.html)\n\n#### Dynamic cluster size\n\nThe size of a cluster can be adjusted on the fly *([Example](http://sintef-9012.github.io/PruneCluster/examples/random.10000-size.html))*\n\n#### Filtering\nThe markers can be filtered easily with no performance cost.\n\n\n### Usage\n```html\n\t\u003c!-- In \u003chead\u003e --\u003e\n\t\u003clink rel=\"stylesheet\" href=\"http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css\"/\u003e\n\n\t\u003c!-- In \u003chead\u003e or before \u003c/body\u003e --\u003e\n\t\u003cscript src=\"http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js\"\u003e\u003c/script\u003e\n\t\u003cscript src=\"PruneCluster/dist/PruneCluster.js\"\u003e\u003c/script\u003e\n```\n\n```javascript\nvar pruneCluster = new PruneClusterForLeaflet();\n\n...\nvar marker = new PruneCluster.Marker(latitude, longitude);\npruneCluster.RegisterMarker(marker);\n...\n\nleafletMap.addLayer(pruneCluster);\n```\n\n### PruneClusterForLeaflet constructor\nPruneClusterForLeaflet([size](#set-the-clustering-size), margin)\n\nYou can specify the size and margin which affect when your clusters and markers will be merged.\n\nsize defaults to 120 and margin to 20.\n\n#### Update a position\n```javascript\nmarker.Move(lat, lng);\n```\n\n#### Deletions\n```javascript\n// Remove all the markers\npruneCluster.RemoveMarkers();\n\n// Remove a list of markers\npruneCluster.RemoveMarkers([markerA,markerB,...]);\n```\n\n#### Set the category\nThe category can be a number or a string, but in order to minimize the performance cost, it is recommended to use numbers between 0 and 7.\n```javascript\nmarker.category = 5;\n```\n\n#### Set the weight\n```javascript\nmarker.weight = 4;\n```\n\n#### Filtering\n```javascript\nmarker.filtered = true|false;\n```\n\n#### Set the clustering size\nYou can specify a number indicating the area of the cluster. Higher number means more markers \"merged\". *([Example](http://sintef-9012.github.io/PruneCluster/examples/random.10000-size.html))*\n```javascript\npruneCluster.Cluster.Size = 87;\n```\n\n#### Apply the changes\n\n**Must be called when ANY changes are made.**\n\n```javascript\npruneCluster.ProcessView();\n```\n\n#### Add custom data to marker object\n\nEach marker has a data object where you can specify your data.\n```javascript\nmarker.data.name = 'Roger';\nmarker.data.ID = '76ez';\n```\n\n#### Setting up a Leaflet icon or a Leaflet popup\n\nYou can attach to the markers an icon object and a popup content\n```javascript\nmarker.data.icon = L.icon(...);  // See http://leafletjs.com/reference.html#icon\nmarker.data.popup = 'Popup content';\n```\n\n#### Faster leaflet icons\n\nIf you have a lot of markers, you can create the icons and popups on the fly in order to improve their performance.\n\n```javascript\nfunction createIcon(data, category) {\n    return L.icon(...);\n}\n\n...\n\nmarker.data.icon = createIcon;\n```\n\nYou can also override the PreapareLeafletMarker method. You can apply listeners to the markers here.\n\n```javascript\npruneCluster.PrepareLeafletMarker = function(leafletMarker, data) {\n    leafletMarker.setIcon(/*... */); // See http://leafletjs.com/reference.html#icon\n    //listeners can be applied to markers in this function\n    leafletMarker.on('click', function(){\n    //do click event logic here\n    });\n    // A popup can already be attached to the marker\n    // bindPopup can override it, but it's faster to update the content instead\n    if (leafletMarker.getPopup()) {\n        leafletMarker.setPopupContent(data.name);\n    } else {\n        leafletMarker.bindPopup(data.name);\n    }\n};\n```\n\n#### Setting up a custom cluster icon\n```javascript\npruneCluster.BuildLeafletClusterIcon = function(cluster) {\n    var population = cluster.population, // the number of markers inside the cluster\n        stats = cluster.stats; // if you have categories on your markers\n\n    // If you want list of markers inside the cluster\n    // (you must enable the option using PruneCluster.Cluster.ENABLE_MARKERS_LIST = true)\n    var markers = cluster.GetClusterMarkers() \n        \n    ...\n    \n    return icon; // L.Icon object (See http://leafletjs.com/reference.html#icon);\n};\n```\n\n#### Listening to events on a cluster\n\nTo listen to events on the cluster, you will need to override the ```BuildLeafletCluster``` method. A click event is already specified on m, but you can add other events like mouseover, mouseout, etc. Any events that a Leaflet marker supports, the cluster also supports, since it is just a modified marker. A full list of events can be found [here](http://leafletjs.com/reference.html#marker-click).\n\nBelow is an example of how to implement mouseover and mousedown for the cluster, but any events can be used in place of those.\n```javascript\npruneCluster.BuildLeafletCluster = function(cluster, position) {\n      var m = new L.Marker(position, {\n        icon: pruneCluster.BuildLeafletClusterIcon(cluster)\n      });\n\n      m.on('click', function() {\n        // Compute the  cluster bounds (it's slow : O(n))\n        var markersArea = pruneCluster.Cluster.FindMarkersInArea(cluster.bounds);\n        var b = pruneCluster.Cluster.ComputeBounds(markersArea);\n\n        if (b) {\n          var bounds = new L.LatLngBounds(\n            new L.LatLng(b.minLat, b.maxLng),\n            new L.LatLng(b.maxLat, b.minLng));\n\n          var zoomLevelBefore = pruneCluster._map.getZoom();\n          var zoomLevelAfter = pruneCluster._map.getBoundsZoom(bounds, false, new L.Point(20, 20, null));\n\n          // If the zoom level doesn't change\n          if (zoomLevelAfter === zoomLevelBefore) {\n            // Send an event for the LeafletSpiderfier\n            pruneCluster._map.fire('overlappingmarkers', {\n              cluster: pruneCluster,\n              markers: markersArea,\n              center: m.getLatLng(),\n              marker: m\n            });\n\n            pruneCluster._map.setView(position, zoomLevelAfter);\n          }\n          else {\n            pruneCluster._map.fitBounds(bounds);\n          }\n        }\n      });\n      m.on('mouseover', function() {\n        //do mouseover stuff here\n      });\n      m.on('mouseout', function() {\n        //do mouseout stuff here\n      });\n\n      return m;\n    };\n};\n```\n\n#### Redraw the icons\n\nMarker icon redrawing with a flag:\n\n```javascript\nmarker.data.forceIconRedraw = true;\n\n...\n\npruneCluster.ProcessView();\n```\n\nRedraw all the icons:\n```javascript\npruneCluster.RedrawIcons();\n```\n\n### Acknowledgements\n\nThis library is developed in context of the [BRIDGE](http://www.bridgeproject.eu/en) project.\n\n### Licence\n\nThe source code of this library is licensed under the MIT License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmonkeymars%2Fprunecluster","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmonkeymars%2Fprunecluster","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmonkeymars%2Fprunecluster/lists"}