Code Monkey home page Code Monkey logo

fbannotationclustering's Introduction

FBAnnotationClustering

Version Carthage compatible Platform

FBAnnotationClustering is no longer maintained. All issues and pull request will not be checked.

FBAnnotationClustering is an iOS library for clustering map notifications in an easy and performant way. Check out the blog post about it.

FBAnnotationClustering example

Usage

Create your clustering manager (and initialize with annotations or add annotations later):

self.clusteringManager = [[FBClusteringManager alloc] initWithAnnotations:arrayOfAnnotations];

Implement MKMapView delegate method mapView:regionDidChangeAnimated: to display annotations grouped in clusters on the map. An example of implementation:

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
    [[NSOperationQueue new] addOperationWithBlock:^{
        double scale = self.mapView.bounds.size.width / self.mapView.visibleMapRect.size.width;
        NSArray *annotations = [self.clusteringManager clusteredAnnotationsWithinMapRect:mapView.visibleMapRect withZoomScale:scale];
        
        [self.clusteringManager displayAnnotations:annotations onMapView:mapView];
    }];
}

Important: Call the method mapView:regionDidChangeAnimated: whenever you want to refresh currently visible map rectangle by yourself (for example, if you added annotations to clusteringManager)

All clusters will have FBAnnotationCluster class, so when MKMapView delegate methods are called, you can check if current annotation is cluster by checking its class. For example:

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{   
    if ([annotation isKindOfClass:[FBAnnotationCluster class]]) {
        FBAnnotationCluster *cluster = (FBAnnotationCluster *)annotation;
        NSLog(@"Annotation is cluster. Number of annotations in cluster: %lu", (unsigned long)cluster.annotations.count);
    } else {
		NSLog(@"Normal annotation.")
    }	
        
    ...
} 

To run the example project; clone the repo, and run pod install from the Example directory first.

Requirements

  • iOS SDK 6
  • ARC

Installation

FBAnnotationClustering is available through CocoaPods, to install it simply add the following line to your Podfile:

pod "FBAnnotationClustering"

If you don't like Cocapods, you can add all files from FBAnnotationClustering directory to your project.

TODO

  • replace NSRecursiveLock with GCD serial queue

  • removeAnnotations: method

      /**
       Remove array of annotations from current annotation collection.
    
       @param annotations Custom annotation objects.
       */
      - (void)removeAnnotations:(NSArray *)annotations;
    

Author

Filip Beć, [email protected]

Credits

FBAnnotationClustering is based on a blog post written by thoughtbot.

Maintained and sponsored by Infinum.

License

FBAnnotationClustering is available under the MIT license. See the LICENSE file for more info.

fbannotationclustering's People

Contributors

aalfare avatar anacar avatar dundo7 avatar filipbec avatar humblehacker avatar javery avatar streeter avatar waterskier2007 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fbannotationclustering's Issues

Have 5 annotations at same location, but on zoom they are not separated

I have 5 users in the same location and the cluster shows title as 5. Latitude and longitude are same for those users. So, as i zoom in, the cluster shows the 5 number only. The cluster is not being separated into single annotations. Everytime i zoom, the mapview delegate is called, but the cluster is not showing the separate pins at any zoom level... Can i have a solution for this..

Thanks.

No hack to remove annotations?

I see in the todo, it is planned to make a method to remove the annotation from the clustering manager. Until then, is there any hack we can use to do this? I looked through previous issues but didn't see anything. I tried self.mapView.removeAnnotations and that did not work either.

Is there a way to achieve cluster onclick?

I'm looking to implement an onclick event when a cluster is clicked in which the map will zoom in and display the sub clusters/pins. How would I go about implementing this?

How to show the number of annotations in the pin?

In this screenshot:
https://github.com/infinum/FBAnnotationClustering/blob/master/Images/example.png
I see how the number of annotations contained in a cluster is shown.
I guess I have to create a custom MKPinAnnotationView and use it inside viewForAnnotation, but not sure?
Do you create a UIImage in real time and use like:
MKPinAnnotationView* userAnnotationView....
userAnnotationView.image...
?

Thanks for suggestions! I really want to create something similar to that screenshot :)

mapView didAddAnnotationViews being falsely called.

The aforementioned function is being called with non-leaf annotation clusters upon panning of the map. I'm trying to call an animation on newly added annotation views like in thoughtbot's application and the animation is being called on all non-leaf annotation clusters whenever the user pans, which is not desired.

//straight from thoughtbot
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
{
    //views contains clusters that it shouldn't when the user pans the map.
    for (UIView *view in views) {
        [self addBounceAnnimationToView:view];
    }
}

- (void)addBounceAnnimationToView:(UIView *)view
{
    CAKeyframeAnimation *bounceAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];

    bounceAnimation.values = @[@(0.05), @(1.1), @(0.9), @(1)];

    bounceAnimation.duration = 0.6;
    NSMutableArray *timingFunctions = [[NSMutableArray alloc] initWithCapacity:bounceAnimation.values.count];
    for (NSUInteger i = 0; i < bounceAnimation.values.count; i++) {
        [timingFunctions addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
    }
    [bounceAnimation setTimingFunctions:timingFunctions.copy];
    bounceAnimation.removedOnCompletion = NO;

    [view.layer addAnimation:bounceAnimation forKey:@"bounce"];
}

I can only assume that clusters are always being updated or recalculated whenever the view changes, thereby hitting didAddAnnotationViews more than it's supposed to.

Swift version?

Hello,

I was wondering if and when there are any plans for a Swift version of your library? (Without the need of bridging)

Best,
Sidney

Is there any way to deactivate the clustering?

Hello!
I have a web service to retrieve all the points in the current map section. After that I call the clustering library.
Under a specific condition, I don't want to use the clustering.
Is there any way to deactivate the clustering?
Maybe a specific value in the cellSizeFactorForCoordinator delegate. Don't know.
Thanks.

Reuse current clusters?

Hi,

I have implemented your pod and it works great so far, but after I added some animations with the didAddAnnotationViews method I noticed that the clusters are always added to the map. Is there a way to only add "new" clusters?

If you look at the normal pin implementation, they are animated only once and they remain on the map until they are removed

Is there any way to cluster only some kind of annotations?

I'm searching for a way to cluster only a list of annotations, and keep unclustered the others.
I've achieved this using:
if let annotations = self.clusteringManager.clusteredAnnotations(within: mapView.visibleMapRect, withZoomScale: scale*2) { let allAnnotations: [Any] = self.notClusteringAnnotations + annotations self.clusteringManager.displayAnnotations(allAnnotations, on: mapView) }

Is there a better way?

Min zoom level on a specific annotation without it being clustered

Let's say I have an action outside the map view that need to focus an annotation on the map.
But if the zoom level is too low then I won't see the annotation but the cluster containing the annotation.
So wouldn't it be nice to have a method like
zoomScaleForUnclustered(annotation: MKAnnotation) -> Double?
That give you the zoom scale you need to apply to your map visible rect to display that specific annotation without it being clustered.

Cheers

Need Help

In the following delegate method,

  • (CGFloat)cellSizeFactorForCoordinator:(FBClusteringManager *)coordinator
    I'm return cell size 1.0, But the clusters are overlapping. I need remove cluster overlapping with cell size 1.0. It is possible? Please help me on this. Sorry for my poor english.

Thank You.

Filter Function for Clustered Annotations

Currently there is no simple way to apply a filter to the underlying annotations once the clustering manager is initialized. Have you considered adding a variant of the 'clusteredAnnotationsWithinMapRect' that takes a function or a predicate as a parameter?

I don't understand very well cellSizeFactorForCoordinator

Hello!

I see that the delegate cellSizeFactorForCoordinator docs say:
"Cell size factor will scale size of default cell size. With value smaller than 1.0 cell size will be smaller than default and you will see more clusters on the map. With factor larger than 1.0 cell size will be bigger than default and you will see less clusters on the map."

Can anyone explain me that? What is a cell?
Thanks a lot for your time.

Disable clustering for a certain zoom level

Hello, I have a map that can contain a lot pins that are very close to each other, this could create the situation that the cluster will never divide itself into single pins . Is there a way to disable the clustering, if the zoom level is greater than a certain value, and accordingly reactivate it in case returned minor than a certain value ??
Thanks in advance

dequeueing FBAnnotationClusterView

In your example app in mapView(, viewForAnnotation: ) you dequeue your clusterView but then create a new one

    var clusterView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
    clusterView = FBAnnotationClusterView(annotation: annotation, reuseIdentifier: reuseId)

I could be wrong, but pretty sure you shouldn't be reinstanciating after dequeuing it.

Heres how I dequeue your clusterView which seems to be working well:

    func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
        if let fbAnnotation = annotation as? FBAnnotationCluster {
            var reuseId = "Cluster"
            var clusterView: FBAnnotationClusterView?
            if let dequeuedClusterView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? FBAnnotationClusterView {
                clusterView = dequeuedClusterView
            }
            if clusterView == nil {
                clusterView = FBAnnotationClusterView(annotation: annotation, reuseIdentifier: reuseId)
            }
            else {
                clusterView!.annotation = fbAnnotation
                clusterView!.setTheCount(fbAnnotation.annotations.count)
            }
            return clusterView
        }
    }

Remove Ruby dependency.

Can not get the project to compile without cocoa pods. Useless tool that infests iOS projects.

Ignoring certain annotations when clustering

First, thank you for a great library! It is extremely fast compared to several others that I have tried.

I have two types of annotations on the map: 1) thousands of annotations that I want to be clustered and 2) a few annotations that shouldn't be clustered. I'm (obviously) only adding the annotations that I want clustered to the clustering manager.

After I pan/zoom the map and call ClusteredAnnotationsWithinMapRect and DisplayAnnotations to refresh the clustering, my non-clustered annotations are removed. I reviewed the DisplayAnnotations method and realized that all annotations on the map are being removed (except userLocation), and then the annotations returned from ClusteredAnnotationsWithinMapRect are being added to the map.

I fixed this by adding my non-clustered annotations to the clustered annotations array:

// Get the clustered annotations on the visible map
var annotations = clusteringManager.clusteredAnnotationsWithinMapRect(...)

// Add any annotations that aren't part of the clustering
var toKeep = [MKAnnotation]()
for annotation in mapView.annotations {
    if annotation is ... {
        toKeep.append(...)
    }
}
// Merge arrays
annotations = annotations + toKeep

clusteringManager.displayAnnotations(annotations, onMapView: mapView)

Is this the best way to fix my issue?

FBAnnotationCluster annotations not recycled

Awesome library, thanks for extending Theodore Calmes' quad-tree to be abstract and object-oriented. Lifesaver! In the interest of making it even better I think I found an issue.

I believe there is an issue in the FBClusteringManager function

- (void)displayAnnotations:(NSArray *)annotations onMapView:(MKMapView *)mapView

The NSSet *toKeep is always empty if you put a breakpoint at line NSMutableSet *toAdd = [NSMutableSet setWithSet:after];

The reason it's always empty is because every time you pan the map and call the - (NSArray *)clusteredAnnotationsWithinMapRect:(MKMapRect)rect withZoomScale:(double)zoomScale method, the entire array returned is all new FBAnnotationCluster objects, so when this array is passed into displayAnnotations, none of the FBAnnotationCluster objects in the before set will be equivalent to any of the FBAnnotationCluster objects in the after set - so intersecting the 2 sets will always yield an empty set. I hacked a solution together for my purposes by comparing on lat/long instead of by object reference but it's of course not the cleanest possible solution.

Overlapping cluster

Two clusters are overlapping. How to increase area of cluster? Any Solution about it?

How to prevent cluster from converting into single annotations on zooming in?

When map is zoomed in then cluster is dispersed into single annotations, how can I disable this property of separating annotations in cluster on zooming in? I tried to set its scale = 0.0 in regionDidChangeDelegate, but then it crashed giving reason "floating point value can not be converted to Int because it is either infinite or NaN"

Carthage build error with XCode 10

Here is the error log

/usr/bin/xcrun xcodebuild -project /myproject/Carthage/Checkouts/FBAnnotationClustering/FBAnnotationClustering.xcodeproj -scheme FBAnnotationClustering -configuration Release -derivedDataPath /Users/me/Library/Caches/org.carthage.CarthageKit/DerivedData/10.3_10G8/FBAnnotationClustering/0.2.2 -sdk iphoneos ONLY_ACTIVE_ARCH=NO CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= CARTHAGE=YES archive -archivePath /var/folders/_r/d0zyvbvd6cb6ryq45mk37nm80000gp/T/FBAnnotationClustering SKIP_INSTALL=YES GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=NO CLANG_ENABLE_CODE_COVERAGE=NO STRIP_INSTALLED_PRODUCT=NO (launched in /myproject/Carthage/Checkouts/FBAnnotationClustering)2019-08-30 11:26:14.647 xcodebuild[1361:39273] [MT] DVTPlugInManager: Required plug-in compatibility UUID B89EAABF-783E-4EBF-80D4-A9EAC69F77F2 for GraphQL.ideplugin (com.apollographql.xcode.graphql) not present
User defaults from command line:
    IDEArchivePathOverride = /var/folders/_r/d0zyvbvd6cb6ryq45mk37nm80000gp/T/FBAnnotationClustering
    IDEDerivedDataPathOverride = /Users/me/Library/Caches/org.carthage.CarthageKit/DerivedData/10.3_10G8/FBAnnotationClustering/0.2.2

Build settings from command line:
    CARTHAGE = YES
    CLANG_ENABLE_CODE_COVERAGE = NO
    CODE_SIGN_IDENTITY = 
    CODE_SIGNING_REQUIRED = NO
    GCC_INSTRUMENT_PROGRAM_FLOW_ARCS = NO
    ONLY_ACTIVE_ARCH = NO
    SDKROOT = iphoneos12.4
    SKIP_INSTALL = YES
    STRIP_INSTALLED_PRODUCT = NO

note: Using new build system
note: Planning build
note: Constructing build description
Build system information
warning: The Copy Bundle Resources build phase contains this target's Info.plist file '/myproject/Carthage/Checkouts/FBAnnotationClustering/FBAnnotationClustering/Info.plist'. (in target 'FBAnnotationClustering')

Build system information
warning: duplicate output file '/Users/me/Library/Caches/org.carthage.CarthageKit/DerivedData/10.3_10G8/FBAnnotationClustering/0.2.2/Build/Intermediates.noindex/ArchiveIntermediates/FBAnnotationClustering/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/FBAnnotationClustering.framework/Info.plist' on task: ProcessInfoPlistFile /Users/me/Library/Caches/org.carthage.CarthageKit/DerivedData/10.3_10G8/FBAnnotationClustering/0.2.2/Build/Intermediates.noindex/ArchiveIntermediates/FBAnnotationClustering/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/FBAnnotationClustering.framework/Info.plist /myproject/Carthage/Checkouts/FBAnnotationClustering/FBAnnotationClustering/Info.plist (in target 'FBAnnotationClustering')

Build system information
error: Multiple commands produce '/Users/me/Library/Caches/org.carthage.CarthageKit/DerivedData/10.3_10G8/FBAnnotationClustering/0.2.2/Build/Intermediates.noindex/ArchiveIntermediates/FBAnnotationClustering/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/FBAnnotationClustering.framework/Info.plist':
1) Target 'FBAnnotationClustering' (project 'FBAnnotationClustering') has copy command from '/myproject/Carthage/Checkouts/FBAnnotationClustering/FBAnnotationClustering/Info.plist' to '/Users/me/Library/Caches/org.carthage.CarthageKit/DerivedData/10.3_10G8/FBAnnotationClustering/0.2.2/Build/Intermediates.noindex/ArchiveIntermediates/FBAnnotationClustering/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/FBAnnotationClustering.framework/Info.plist'
2) Target 'FBAnnotationClustering' (project 'FBAnnotationClustering') has process command with output '/Users/me/Library/Caches/org.carthage.CarthageKit/DerivedData/10.3_10G8/FBAnnotationClustering/0.2.2/Build/Intermediates.noindex/ArchiveIntermediates/FBAnnotationClustering/IntermediateBuildFilesPath/UninstalledProducts/iphoneos/FBAnnotationClustering.framework/Info.plist'

** ARCHIVE FAILED **

but I was able to build the lib manually by open FBAnnotationClustering project then remove Info.plist file from Copy Bundle Resources

then run carthage build FBAnnotationClustering

and it works fine.

NSInvalidArgumentException. -[__NSSetM removeObject:]: object cannot be nil

Hello there))
Thanx for the amazing tool you've created!

FBClusteringManager.m line 168
-[FBClusteringManager displayAnnotations:onMapView:]

NSMutableSet *before = [NSMutableSet setWithArray:mapView.annotations];
[before removeObject:[mapView userLocation]];

The app crashes if [mapView userLocation] returns nil

Thanx in advance!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.