hulab / clusterkit Goto Github PK
View Code? Open in Web Editor NEWAn iOS map clustering framework targeting MapKit, Google Maps and Mapbox.
License: MIT License
An iOS map clustering framework targeting MapKit, Google Maps and Mapbox.
License: MIT License
Hi,
I'm using the newer version of cluster kit with mapbox, and when i made zoom in zoom out in map the app crash. The error return is this:
Terminating app due to uncaught exception 'NSRangeException', reason: 'Cannot remove an observer <MGLMapView 0x106922a00> for the key path "coordinate" from <CKCluster 0x1135e7640> because it is not registered as an observer.'
Can you help me?
Regards
I've been attempting to integrate ClusterKit into our app but it seems at certain zoom levels a single annotation may exist in multiple clusters which looks strange. Here is a gif illustrating the issue:
Here you can see that there are just 3 annotations, but when I zoom out to a certain level it goes from clusters of 2 and 1 to clusters of 2 and 2 and then when zooming out more it goes to one cluster of 3. There are actually only 3 annotations so it seems they are mistakenly sharing an annotation at a specific zoom level.
The code I've added so far is pretty straightforward and follows your example quite closely.
I add the algorithm with a custom cell size:
CKNonHierarchicalDistanceBasedAlgorithm *algorithm = [CKNonHierarchicalDistanceBasedAlgorithm new];
algorithm.cellSize = 200;
_mapView.clusterManager.algorithm = algorithm;
_mapView.clusterManager.marginFactor = 1;
Creating MKAnnotationViews and setting the annotation:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]]) {
return nil;
}
MKAnnotationView *mapAnnotationView = nil;
mapAnnotationView = (GWTicketsGroupedByLocationPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:pinAllTicketsAnnotationIdentifier];
if ([annotation isKindOfClass:CKCluster.class]) {
return [[GroupedGigAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pinAllTicketsAnnotationIdentifier];
}
[mapAnnotationView setAnnotation:annotation];
return mapAnnotationView;
}
and updating the clusters when region changes:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
[_mapView.clusterManager updateClustersIfNeeded];
}
Is there something wrong with the distance based algorithm or am I doing something incorrectly?
I have a huge amount of POIs that I can successfully show over on the map. But I also need to search all the POIs within a certain distance from the user location, in a different view.
Is it possible to create one general cluster of annotations, accessing it from different view controllers and perform a search based on the user location?
Whit the standard code (market swift version) in view for Annotation sometimes my location appear as marker, is there a way to hide it?
already tried to force whit mapView.showsUserLocation = false
Hi,
I am trying to integrate your cluster into my project it's quite awesome. I have some clarification. now I am working on a rental project so I need to take maker and I need to show callout view. unfortunately, when I tap marker nothing is happing pls kindly do needful and also when the map is load I need to zoom it on country base I changed specific location but I don't know zooming kindly check it
herewith i attached delegate method screen check it once
` let algorithm = CKNonHierarchicalDistanceBasedAlgorithm()
algorithm.cellSize = 200
mapView.clusterManager.algorithm = algorithm
mapView.clusterManager.marginFactor = 1
mapView.clusterManager.maxZoomLevel = 50
let paris = CLLocationCoordinate2D(latitude: 11.5449, longitude: 104.8922)
mapView.setCenter(paris, animated: false)
`
The Mapbox (and probably google) install directions should include the block of instructions that state that each of the targets is a separate sub package.
This is my custom annotation
class CafeShopAnnotation: MKPointAnnotation {
override var coordinate: CLLocationCoordinate2D {
get {
return CLLocationCoordinate2DMake(self.latitude, self.longitude)
}
set {
self.coordinate = newValue
}
}
override var title: String? {
get {
return self.name
}
set {
self.title = newValue
}
}
override var subtitle: String? {
get {
return self.address
}
set {
self.subtitle = newValue
}
}
var id = ""
var city = ""
var name = ""
var wifi = Double()
var seat = Double()
var quiet = Double()
var tasty = Double()
var cheap = Double()
var music = Double()
var address = ""
var latitude = Double()
var longitude = Double()
var url = ""
var limited_time = ""
var socket = ""
var standing_desk = ""
var mrt = ""
var open_time = ""
}
In viewdidload i will handle my store class transform to custom annotation
but view for annotation cast ckcluster fail
what should i do ?
Sometimes it is very useful to get annotations that are combined under specific cluster to have more flexibility around annotationView text, and not just show count of objects there. Please make it public
Hi Maxep,
Right now I'm working cluster map using this framework(Apple mapkit) on Objective C.
I need to get existed annotations by using annotationAtIndex from CKCluster class.
Right now I can't access that method using "clusterManager".
If I use "clusterWithCoordinate:" method to access "annotationAtIndex" by using CKCluster instance, but I can't get the existed one because it's initializing newly.
Kindly suggest me.
Thanks.
Hello, I'm having this message when trying to install with Cocoapods :
"Unable to find a specification for ClusterKit
"
I'd like to check if there is any implementation for multiple pins in the same coordinates? I think clustering is not enough.
I'm using ClusterKit for Mapbox, it's working decently so far, however there is a serious problem.
When zoomed in, my clusters expand to individual pins. Sometimes these remain even when zoomed out.
My hypothesis is that when you call self.mapView.clusterManager.addAnnotations (for example, from a network call) while an existing clustering update is happening, it ends up plotting both of them.
Hey! How should you add the count to cluster item?
This seem to be happening only when a cluster "has been used" to reveal underlined annotations and becomes hidden when it's time to put them back in.
I have followed the Swift example and my code is largely based on in except for the part where I apply dynamic text on the clusters (cluster count)
Here's my func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?
:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if (annotation is MKUserLocation) {
return nil
}
guard let cluster = annotation as? CKCluster else {
return nil
}
if cluster.count > 1 {
let cView = mapView.dequeueReusableAnnotationView(withIdentifier: ClusterAnnotationIdentifier) ??
CKClusterView(annotation: annotation, reuseIdentifier: ClusterAnnotationIdentifier, count: cluster.count)
return cView
}
return mapView.dequeueReusableAnnotationView(withIdentifier: PointAnnotationIdentifier) ??
CKAnnotationView(annotation: annotation, reuseIdentifier: PointAnnotationIdentifier)
}
And annotations code:
class CKAnnotationView: MKAnnotationView {
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
canShowCallout = true
isDraggable = false
image = UIImage(named: "blue-marker")
}
required init?(coder aDecoder: NSCoder) {
fatalError("Not implemented")
}
}
class CKClusterView: MKAnnotationView {
convenience init(annotation: MKAnnotation?, reuseIdentifier: String?, count: UInt) {
self.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
let icon = "\(count)".to(image: UIImage(named: "cluster-marker")!, atPoint: CGPoint(x: 0, y: 8))
image = icon
}
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
}
override func prepareForReuse() {
super.prepareForReuse()
image = nil
}
required init?(coder aDecoder: NSCoder) {
fatalError("Not implemented")
}
}
class ParkingPointAnnotation: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String?
var subtitle: String?
init(coordinate: CLLocationCoordinate2D, title: String, subtitle: String) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
}
}
Any suggestion where I can take a look in order to debug this?
Hi guys! Do you have plans to support Mapbox version 4.0? ClusterKit is currently dependent of Mapbox 3.6.
Thank you for this amazing lib!
Hello! I'm trying to add some additional alpha animation to collapsing annotationViews animation, but it seems CKClusterManagerDelegate doesn't provide proper methods to do this. By using 'clusterManager performAnimations' delegate method I can only manipulate animation code blocks but not the annotations that are going to animate.
I found a workaround for expanding animation simply by animate alpha separately in mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView])
:
func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) { views.forEach { (annotation) in annotation.alpha = 0.01 UIView.animate(withDuration: 0.5, animations: { annotation.alpha = 1.0 }) } }
But I can't found a workaround for fade out animation on collapsing.
I need this because I have different shapes of annotationViews and the collapse animation because of that, looks a little bit weird.
Please, add the ability to customise animations.
Hello! Thanks for ClusterKit!
I have a project with tons of MGLPointAnnotation (with custom icons) and etc.
I do not use GeoJSON, all points are added dynamically. I found the way how to utilize ClusterKit with annotationViews, and it works, but I have a duplicates for every PointAnnotation and other problems.
Is there any simple way to use this kit for MGLPointAnnotations, not for MGLAnnotationView?
Hi,
I have checked the library but I didn't found how I can put the total number of map PIN covered in the region as compared to other libraries so please let me know if your library provides a way to achieve the same.
Thanks
Hey! I am trying to use this with Swift and GoogleMap. But the documentation is pretty small and it is hard for me to read Objective-c so I pretty much read comments. My problem is that how to add my GMSMarker as annotations into clusterManager
since it is of type CKAnnotation
?
I have Custom marker that inherits from GMSMArker
.
This is what I am trying to do:
for location in self.pointOfInterests{
let annotation = CustomMarker()
annotation.markerID = location.id
annotation.icon = #imageLiteral(resourceName: "MapPin")
annotation.title = location.title
annotation.snippet = location.description
annotation.position = CLLocationCoordinate2D(latitude: location.lat, longitude: lng)
annotation.map = self.mapView
//Now here I should add those markers or annotations to the cluseterManager as self.mapView.addAnnotations(...)
}
In markerFor cluster: CKCluster
I did like this:
func mapView(_ mapView: GMSMapView, markerFor cluster: CKCluster) -> GMSMarker {
let marker = CustomMarker(position: cluster.coordinate)
if cluster.count > 1 {
marker.icon = UIImage(named: "cluster")
} else {
marker.icon = UIImage(named: "marker")
marker.title = cluster.title
}
return marker;
}
What should I do?
If I choose to exclude an annotation from being clustered using func clusterManager(_ clusterManager: CKClusterManager, shouldClusterAnnotation annotation: MKAnnotation) -> Bool
then that annotation is not displayed on the map.
Is this intended behaviour?
I use Carthage. I always get error:
'ClusterKit/CKClusterManager.h' file not found
Can u plz help, Got error while run app
-[GMSMapView clusterManager]: unrecognized selector sent to instance 0x7f84d108ea00
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[GMSMapView clusterManager]: unrecognized selector sent to instance 0x7f84d108ea00'
Hi there, thank you for this wonderful library! I was hoping you could help resolve the following issue. It appears as though MKAnnotations in an NSArray do not match those in a Swift Array. Do you know why this could be the case?
func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {
guard let cluster = annotation as? CKCluster else {
return nil
}
if cluster.count > 1 {
for clusteredAnnotation in cluster.annotations { // Fatal error: NSArray element failed to match the Swift Array Element type
print(clusteredAnnotation.coordinate)
}
return self.mapView.dequeueReusableAnnotationView(withIdentifier: CKMapViewDefaultAnnotationViewReuseIdentifier) ?? MBXAnnotationView(annotation: annotation, reuseIdentifier: CKMapViewDefaultAnnotationViewReuseIdentifier)
}
return mapView.dequeueReusableAnnotationView(withIdentifier: CKMapViewDefaultAnnotationViewReuseIdentifier) ??
MBXAnnotationView(annotation: annotation, reuseIdentifier: CKMapViewDefaultAnnotationViewReuseIdentifier)
}
Hello,
I keep an array of my annotations that I give to the clusterManager :
var myArray = [MyAnnotationThatExtendsCKAnnotation]() // class member
// I add a bunch of annotations in the array
map.clusterManager.annotations = myArray
At a later time I would like to access one of my annotation's corresponding annotation view (outside of mapView(_:viewFor:)
) to update it (basically my annotations have a different visual for different states, state that I obtain after a network call)
I've tried something like this :
let av = map.view(for: myArray[0]) as? MyAnnotationView
but I always end up with nil
value.
Any idea why ? Would it be possible to update annotation views without removing/adding them back every time ?
Thanks.
Currently, when a cluster contains multiple annotations with exact same coordinates, they do not expand (display child annotations) when tapped on or zoomed in. Is there a way to add handle such cases or perhaps add displacement to this annotations so they're displayed separately.
Hi, I have an error to add the pod for mapbox
[!] Unable to satisfy the following requirements:
ClusterKit/Mapbox
required by Podfile
None of your spec sources contain a spec satisfying the dependency: ClusterKit/Mapbox
.
Can you help me ?
I am working on swift 4
/Users/mac/Documents/Ashish/Project/Working Project/BitBucket/eventyr-ios-master/:1:10: '/Users/mac/Documents/Ashish/Project/Working Project/BitBucket/eventyr-ios-master/eventyr/Application/eventyr-Prefix.pch' file not found
How to customize MGLPointAnnotation class for Mapbox using ClusterKit. Seems like ClusterKit is using MKAnnotation.
At the moment, we put the annotations in an array of Сluster Manager:
mapView.clusterManager.annotations = annotations
But, what should I do if I want to have two different layers. For example, shops will cluster in one layer and cultural monuments in another.
I have two arrays
var news: [NewsAnnotation]
var monuments: [MonumentsAnnotation]
Accordingly, these two arrays should not cluster together. And should not be displayed on the map as a single layer.
Any ideas?
I Used MapBox.
Hello !
So I've worked with this framework for swift with MKMapView, and I'm using a system where I show the number of annotations inside a cluster. The issue I've found is that if we have 2 nearby clusters and the algorithm recalculates such that one annotation moves from one cluster to the other, no animation will occur and the change is instant.
This issue isn't really apparent in the examples provided because it doesn't show how many annotations are inside a cluster, but if you use this code you can see it:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "annotation") ??
newAnnotationView(forAnnotation: annotation)
if let cluster = annotation as? CKCluster {
let label = annotationView.viewWithTag(1235) as! UILabel
if cluster.count > 1 {
annotationView.canShowCallout = false
annotationView.image = UIImage(named: "cluster")
label.text = "\(cluster.count)"
label.isHidden = false
} else {
label.isHidden = true
annotationView.canShowCallout = true
annotationView.image = UIImage(named: "marker")
}
}
return annotationView;
}
private func newAnnotationView(forAnnotation annotation: MKAnnotation) -> MKAnnotationView {
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "annotation")
let centerText = UILabel()
centerText.translatesAutoresizingMaskIntoConstraints = false
centerText.tag = 1235
centerText.textColor = UIColor.cyan
annotationView.addSubview(centerText)
annotationView.addConstraint(NSLayoutConstraint(item: centerText, attribute: NSLayoutAttribute.centerX, relatedBy: NSLayoutRelation.equal, toItem: annotationView, attribute: NSLayoutAttribute.centerX, multiplier: 1, constant: 0))
annotationView.addConstraint(NSLayoutConstraint(item: centerText, attribute: NSLayoutAttribute.centerY, relatedBy: NSLayoutRelation.equal, toItem: annotationView, attribute: NSLayoutAttribute.centerY, multiplier: 1, constant: 0))
return annotationView
}
Find a location and zoom in slightly or zoom out slightly and you will notice that some clusters change the amount of annotations even though nothing goes in or out of them.
I installed the lib using cocoapods and tried to implement it in a project but I noticed the clusterManager
property is missing from MKMapView
.
I looked into the ClusterKit
folder containing the sources files (inside the Pods
folder) and only the Core
folder is here but not the MapKit
or GoogleMaps
folders.
I suppose these folder should be present right?
Hello,
I'm trying to implement ClusterKit,
but can't seem to correct 2 errors,
first is the title
Looking into CKCluster.h and m, I can't seem to see that either annotations and its getter functions are public
second, the pod subspec for GoogleMaps doesn't seem to be available
ClusterKit is causing a flickering issue on custom annotation views using MapKit.
I have tried solving this issue by using: - addAnnotations(...)
and - removeAnnotations(...)
,
but that doesn't seam to solve the problem.
I'm calling - updateClustersIfNeeded
in -mapView(_:, regionDidChangeAnimated:)
as described in the documentation.
Tested with:
HI, awesome framework, really easy to handle clustering, I'm interested to know if u have some suggestion how u would handle adding circles for the pin, in my case is basically accuracy circle which I use GMSCircle to show that. But with cluster GMSMapViewDataSource
there is no way to add the circle, I wonder if u know any workaround for any delegates call that I can use to add the circles my self, I only want to add the circles when the pins are unclustred.
Thanks.
is there a way to define a minimum number of itens before clustering?
Can you make the project compatible with swift?
I need to apply clustering algorithm on bunch of CLLocationCoordinate2D points and just achieve resulting cluster's CLLocationCoordinate2D points. Is there a way to do this without using map view?
Hi
Great work with the Kit! Integration was easy and it actually works quite fast and reliable unlike the frameworks I have experimented before. However I think I found a special case that's not handled.
When navigating in GoogleMaps so that the view covers the international date line (longitude 180 / -180) all clusters on the map disappear. They reappear immediately when moving completely on either side of the line. Even though this is more of an inconvinience than a real blocker it gives an incomplete user experience and I would love to have this working. See the gif below for an example.
Even with this issue the ClusterKit is great, thank you. :)
Is it possible to show the clusters on visible area only?
Thanks.
Hello! Is there a way to detect nearest annotations around user's tap? In original sdk we have this method:
CGPoint spot = [self.lastTap locationInView:self];
NSArray* features = [self visibleFeaturesAtPoint:spot];
Maybe something similar possible in a clusterkit? (I need show a "more menu" when user long-tap on a some annotationView)
Hi,
I'm want to give your framework a try but I'm not able to install it pod install
gives following errors:
Fetching podspec for `ClusterKit` from `../.`
[!] The following pods are integrated into targets that do not have the same Swift version:
- ClusterKit/Core required by Example-objc (Swift 3.0), Example-swift (Swift 4.0)
- ClusterKit/MapKit required by Example-objc (Swift 3.0), Example-swift (Swift 4.0)
- ClusterKit/Mapbox required by Example-objc (Swift 3.0), Example-swift (Swift 4.0)
- Mapbox-iOS-SDK required by Example-objc (Swift 3.0), Example-swift (Swift 4.0)
- GoogleMaps required by Example-objc (Swift 3.0), Example-swift (Swift 4.0)
- GoogleMaps/Base required by Example-objc (Swift 3.0), Example-swift (Swift 4.0)
- GoogleMaps/Maps required by Example-objc (Swift 3.0), Example-swift (Swift 4.0)
Hey, guys. I would like to thank you for this library. But I have a question. Is it possible to display the number of objects in the cluster next to the cluster icon or inside the cluster icon? I use Mapbox.
Hello there,
ClusterKit is great to display a huge amount of annotations but does exit a way to filter the annotations by, for example, certain category?
hi, first of all this extension is great! But for now i 'm not able to get it works:
I have a custom class for annotations, i added CKAnnotation as another issue suggested me, but when i try to add an annotation to cluster:
self.mapView.clusterManager.annotations = annotation
i get: can not assign value of type MyAnnotation to CKAnnotation.
What's wrong?
here's the code:
` import UIKit
import MapKit
import ClusterKit
class MyAnnotations: NSObject, MKAnnotation, CKAnnotation{
weak public var cluster: CKCluster?
var coordinate: CLLocationCoordinate2D
var title: String?
var subtitle: String?
var name: String?
var size: String?
var user: String?
var owner: String?
var image: String?
var latLoc: Double?
var lonLoc: Double?
var itemId: String?
init(coordinate: CLLocationCoordinate2D) {
self.coordinate = coordinate
}
} `
Hi, I'm trying to implement the library but I'm stuck, I have an array of MKAnnotation for my locations but the cluestermanager expects CKAnnotation objects...
in mapbox:
I can not get annotationView when use:
guard let annotationView = mapView.view(for: annotation) else {return}
which can get before use Clusterkit
I am trying to work run the example project but it fails with this error:
dyld: Library not loaded: @rpath/GeoJSONSerialization.framework/GeoJSONSerialization
Also, when I tried setting up my own swift project, I get following compile time error:
Value of type 'GMSMapView' has no member 'clusterManager'
Here is my podfile:
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
target 'mapcluster' do
# Comment this line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
# Pods for mapcluster
pod 'ClusterKit'
pod 'GoogleMaps', '~> 2.2'
pod 'ClusterKit/MapKit'
end
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.