{"id":15037386,"url":"https://github.com/efremidze/cluster","last_synced_at":"2025-05-15T17:08:23.429Z","repository":{"id":46640062,"uuid":"88143824","full_name":"efremidze/Cluster","owner":"efremidze","description":"Easy Map Annotation Clustering 📍","archived":false,"fork":false,"pushed_at":"2023-11-20T08:14:25.000Z","size":6175,"stargazers_count":1280,"open_issues_count":24,"forks_count":121,"subscribers_count":20,"default_branch":"master","last_synced_at":"2025-05-15T17:08:16.337Z","etag":null,"topics":["annotations","apple","carthage","cluster","clustering","cocoapods","ios","map","mapkit","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/efremidze.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-04-13T08:40:54.000Z","updated_at":"2025-05-15T04:07:46.000Z","dependencies_parsed_at":"2024-01-13T04:22:38.137Z","dependency_job_id":null,"html_url":"https://github.com/efremidze/Cluster","commit_stats":{"total_commits":175,"total_committers":14,"mean_commits":12.5,"dds":"0.12571428571428567","last_synced_commit":"a04bca1ecfc378d66195144ab8e0dccff26435d0"},"previous_names":[],"tags_count":45,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/efremidze%2FCluster","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/efremidze%2FCluster/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/efremidze%2FCluster/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/efremidze%2FCluster/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/efremidze","download_url":"https://codeload.github.com/efremidze/Cluster/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254384988,"owners_count":22062422,"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":["annotations","apple","carthage","cluster","clustering","cocoapods","ios","map","mapkit","swift"],"created_at":"2024-09-24T20:34:30.258Z","updated_at":"2025-05-15T17:08:18.421Z","avatar_url":"https://github.com/efremidze.png","language":"Swift","readme":"![Cluster](https://raw.githubusercontent.com/efremidze/Cluster/master/Images/logo.png)\n\n[![Build Status](https://travis-ci.org/efremidze/Cluster.svg?branch=master)](https://travis-ci.org/efremidze/Cluster)\n[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![Language](https://img.shields.io/badge/Swift-5-orange.svg?style=flat)](https://swift.org)\n[![Version](https://img.shields.io/cocoapods/v/Cluster.svg?style=flat)](http://cocoapods.org/pods/Cluster)\n[![License](https://img.shields.io/cocoapods/l/Cluster.svg?style=flat)](http://cocoapods.org/pods/Cluster)\n[![Platform](https://img.shields.io/cocoapods/p/Cluster.svg?style=flat)](http://cocoapods.org/pods/Cluster)\n\nCluster is an easy map annotation clustering library. This repository uses an efficient method (QuadTree) to aggregate pins into a cluster.\n\n![Demo Screenshots](https://raw.githubusercontent.com/efremidze/Cluster/master/Images/demo.png)\n\n- [Features](#features)\n- [Requirements](#requirements)\n- [Demo](#demo)\n- [Installation](#installation)\n- [Usage](#usage)\n- [Communication](#communication)\n- [Mentions](#mentions)\n- [Credits](#credits)\n- [License](#license)\n\n## Features\n\n- [x] Adding/Removing Annotations\n- [x] Clustering Annotations\n- [x] Multiple Managers\n- [x] Dynamic Cluster Disabling\n- [x] Custom Cell Size\n- [x] Custom Annotation Views\n- [x] Animation Support\n- [x] [Documentation](https://efremidze.github.io/Cluster)\n\n## Requirements\n\n- iOS 8.0+\n- Xcode 9.0+\n- Swift 5 (Cluster 3.x), Swift 4 (Cluster 2.x), Swift 3 (Cluster 1.x)\n\n## Demo\n\nThe [Example](Example) is a great place to get started. It demonstrates how to:\n\n- integrate the library\n- add/remove annotations\n- reload annotations\n- configure the annotation view\n- configure the manager\n\n\u003cimg src=\"/Images/demo.gif\" width=\"250\" /\u003e\n\n```\n$ pod try Cluster\n```\n\n## Installation\n\nCluster is available via CocoaPods and Carthage.\n\n### CocoaPods\n\nTo install Cluster with [CocoaPods](http://cocoapods.org/), add this to your `Podfile`:\n\n```\npod \"Cluster\"\n```\n\n### Carthage\n\nTo install Cluster with [Carthage](https://github.com/Carthage/Carthage), add this to your `Cartfile`:\n\n```\ngithub \"efremidze/Cluster\"\n```\n\n## Usage\n\n### The Basics\nThe `ClusterManager` class generates, manages and displays annotation clusters.\n\n```swift\nlet clusterManager = ClusterManager()\n```\n\n### Adding an Annotation\n\nCreate an object that conforms to the `MKAnnotation` protocol, or extend an existing one. Next, add the annotation object to an instance of `ClusterManager` with `add(annotation:)`.\n\n```swift\nlet annotation = Annotation(coordinate: CLLocationCoordinate2D(latitude: 21.283921, longitude: -157.831661))\nmanager.add(annotation)\n```\n\n### Configuring the Annotation View\n\nImplement the map view’s `mapView(_:viewFor:)` delegate method to configure the annotation view. Return an instance of `MKAnnotationView` to display as a visual representation of the annotations.\n\nTo display clusters, return an instance of `ClusterAnnotationView`.\n\n```swift\nextension ViewController: MKMapViewDelegate {\n    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -\u003e MKAnnotationView? {\n        if let annotation = annotation as? ClusterAnnotation {\n            return CountClusterAnnotationView(annotation: annotation, reuseIdentifier: \"cluster\")\n        } else {\n            return MKPinAnnotationView(annotation: annotation, reuseIdentifier: \"pin\")\n        }\n    }\n}\n```\n\nFor performance reasons, you should generally reuse `MKAnnotationView` objects in your map views. See the [Example](Example) to learn more.\n\n#### Customizing the Appearance\n\nThe `ClusterAnnotationView` class exposes a `countLabel` property. You can subclass `ClusterAnnotationView` to provide custom behavior as needed. Here's an example of subclassing the  `ClusterAnnotationView` and customizing the layer `borderColor`.\n\n```swift\nclass CountClusterAnnotationView: ClusterAnnotationView {\n    override func configure() {\n        super.configure()\n\n        self.layer.cornerRadius = self.frame.width / 2\n        self.layer.masksToBounds = true\n        self.layer.borderColor = UIColor.white.cgColor\n        self.layer.borderWidth = 1.5\n    }\n}\n```\n\nSee the [AnnotationView](Example/AnnotationView.swift) to learn more.\n\n#### Annotation Styling\n\nYou can customize the appearance of the `StyledClusterAnnotationView` by setting the `style` property of the annotation.\n\n```swift\nlet annotation = Annotation(coordinate: CLLocationCoordinate2D(latitude: 21.283921, longitude: -157.831661))\nannotation.style = .color(color, radius: 25)\nmanager.add(annotation)\n```\n\nSeveral styles are available in the `ClusterAnnotationStyle` enum:\n- `color(UIColor, radius: CGFloat)` - Displays the annotations as a circle. \n- `image(UIImage?)` - Displays the annotation as an image.\n\nOnce you have added the annotation, you need to return an instance of the `StyledClusterAnnotationView` to display the styled annotation.\n\n```swift\nfunc mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -\u003e MKAnnotationView? {\n    if let annotation = annotation as? ClusterAnnotation {\n        return StyledClusterAnnotationView(annotation: annotation, reuseIdentifier: identifier, style: style)\n    }\n}\n```\n\n### Removing Annotations\n\nTo remove annotations, you can call `remove(annotation:)`. However the annotations will still display until you call `reload()`.\n\n```swift\nmanager.remove(annotation)\n```\n\nIn the case that `shouldRemoveInvisibleAnnotations` is set to `false`, annotations that have been removed may still appear on map until calling `reload()` on visible region.\n\n### Reloading Annotations\n\nImplement the map view’s `mapView(_:regionDidChangeAnimated:)` delegate method to reload the `ClusterManager` when the region changes.\n\n```swift\nfunc mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {\n    clusterManager.reload(mapView: mapView) { finished in\n        // handle completion\n    }\n}\n```\n\nYou should call `reload()` anytime you add or remove annotations.\n\n### Configuring the Manager\n\nThe `ClusterManager` class exposes several properties to configure clustering:\n\n```swift\nvar zoomLevel: Double // The current zoom level of the visible map region.\nvar maxZoomLevel: Double // The maximum zoom level before disabling clustering.\nvar minCountForClustering: Int // The minimum number of annotations for a cluster. The default is `2`.\nvar shouldRemoveInvisibleAnnotations: Bool // Whether to remove invisible annotations. The default is `true`.\nvar shouldDistributeAnnotationsOnSameCoordinate: Bool // Whether to arrange annotations in a circle if they have the same coordinate. The default is `true`.\nvar distanceFromContestedLocation: Double // The distance in meters from contested location when the annotations have the same coordinate. The default is `3`.\nvar clusterPosition: ClusterPosition // The position of the cluster annotation. The default is `.nearCenter`.\n```\n\n### ClusterManagerDelegate\n\nThe  `ClusterManagerDelegate` protocol provides a number of functions to manage clustering and configure cells.\n\n```swift\n// The size of each cell on the grid at a given zoom level.\nfunc cellSize(for zoomLevel: Double) -\u003e Double? { ... }\n\n// Whether to cluster the given annotation.\nfunc shouldClusterAnnotation(_ annotation: MKAnnotation) -\u003e Bool { ... }\n```\n\n## Communication\n\n- If you **found a bug**, open an issue.\n- If you **have a feature request**, open an issue.\n- If you **want to contribute**, submit a pull request.\n\n## Mentions\n\n- [Natasha The Robot's Newsleter 128](https://swiftnews.curated.co/issues/128#start)\n- [Top 5 iOS Libraries May 2017](https://medium.cobeisfresh.com/top-5-ios-libraries-may-2017-6e3ac5077473)\n\n## Credits\n\n* https://github.com/ribl/FBAnnotationClusteringSwift\n* https://github.com/choefele/CCHMapClusterController\n* https://github.com/googlemaps/google-maps-ios-utils\n* https://github.com/hulab/ClusterKit\n\n## License\n\nCluster is available under the MIT license. See the LICENSE file for more info.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fefremidze%2Fcluster","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fefremidze%2Fcluster","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fefremidze%2Fcluster/lists"}