Code Monkey home page Code Monkey logo

cchmapclustercontroller's People

Contributors

aoptionu avatar choefele avatar damarte avatar eikebartels avatar jkrumow avatar nferruzzi avatar onato avatar robertjpayne avatar rosskimes avatar tspacek avatar waffle-with-pears 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

cchmapclustercontroller's Issues

Crash Report

Hey,
I've been looking into my crash reports and i found one that happened multiple of times. it's inside CCHMapClusterControllerUtils.m so i am not really able to debug the issue
it's line 53 CCHMapClusterControllerFindVisibleAnnotation
the error is

Fatal Exception: NSInvalidArgumentException
-[__NSCFString containsObject:]: unrecognized selector sent to instance 0x1d31d780

line 53 is

if ([visibleAnnotation.annotations containsObject:annotation]) {

so i don't understand how visibleAnnotation.annotations was pointing to a NSString.

could you help me in any way?

Disabling cluster annotation interaction

If I am doing another method on the map that requires touches and want it so the user isn't able to click on the cluster annotation or any annotation for that matter and it do anything, just to have them disabled, is there a way to do this?

Thank You
Blake Mitchell

Invalid map length error

i changed my map view constraints to now fill the view to the top because i occasionally hide the navigation bar. when i present a modal view and then close it
i get an error
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid map length'
on line CCHMapClusterController/CCHMapClusterControllerUtils.m:90

calloutAccessoryControlTapped not called

Probably I've missed something here. Question is; should mapView:annotationView:calloutAccessoryControlTapped: supposed to work or should I use something else?
Not called in either the example project or in my own project.

Problem to understand how the display works for annotations

Hi, first thank you for this project I am really forward to digup more about it. But There is something I can't figure out. I am trying to display one single annotation in France with both JSON and CSV. Can you explain me why it does not work even if I am changing the region, the annotation is always display lat: 0 long: 0, like it does not have any coordinate.

Total Annotations in Cell

Just getting start with CCHMapClusterController. I would like to use it for bikemap.

I need to display how many annotations are in a grid cell like you can see here…

http://www.bikemap.net/en/?tab=top#/z6/50.00773,-4.57032/terrain

It looks as though this is not possible at the moment.

Could you point me in the right direction?

It appears that I need to refactor the CCHMapClusterAnnotation part in updateAnnotationsWithCompletionHandler: so I can override it in a subclass which sums up the visible annotation's sub-annotations.

It would be nicer if I could somehow work this out from within the mapClusterController:titleForMapClusterAnnotation: delegate method.

When dynamically adding and deleting pins some pins get re-copied

For instance:
If I add 100 annotations in NJ. then I move to PA and add new pins (and still leaving the pins in nj). Then scroll back to the pins in jersey they seem to "double", meaning there are two annotations in the place of one for whatever reason in the same geo (note I do not fetch for more pins).

Ensure all completion handlers are called on main thread

All the callbacks from CCHMapClusterController should be delegated to the main queue as it's most likely to always be used in conjunction with other main thread work and a MKMapView.

Right now many of the completionHandlers are always or sometimes set directly to an NSOperation's completionBlock property. When doing so the thread in which the callback is made is undefined as it will be whatever thread the NSOperation runs on.

Type casting ??

Hi
Type casting not working in my code.

  • (void)mapClusterController:(CCHMapClusterController *)mapClusterController willReuseMapClusterAnnotation:(CCHMapClusterAnnotation *)mapClusterAnnotation
    {
    ClusterAnnotationView *clusterAnnotationView = (ClusterAnnotationView *)[self.mapView viewForAnnotation:mapClusterAnnotation];
    clusterAnnotationView.count = mapClusterAnnotation.annotations.count;
    clusterAnnotationView.uniqueLocation = mapClusterAnnotation.isUniqueLocation;
    }

clusterAnnotationView is already MkpinAnnotation object. So give "[MKPinAnnotationView setCount:]: unrecognized selector sent to instance" error.

What should I do??

Thanks

How do i remove all annotations?!

i use
[_mapView removeAnnotations:_mapView.annotations];
to remove the annotations from the map but they come back. is this because i haven't removed them from my CCHMapClusterController?
if so how can i remove them?

iOS Example: Tapping "Reset" button results in another bunch of annotations added to the map without clearing the old ones.

Tapping "Reset" button results in another bunch of annotations added to the map without clearing the old ones.

Steps to reproduce:

  1. Launch CCHMapClusterController Example iOS
  2. Wait for map fully loaded
  3. Tap "Reset"

Expected results:
Map is reloaded with the same number of annotations

Actual results:
The same number of annotations is added to the map, doubling the numbers displayed for the first time, 3x, 4x and so on, every time you tap "Reset".

2014-10-27 18 03 12
2014-10-27 18 03 02
2014-10-27 18 02 55

Problem with disappearing annotation callouts

I have a map view using your great CCHMapClusterController. Clusters with more than one annotations are shown with a circle and a number, clusters with a single annotation are shown with a standard pin. Tapping on clusters with more than one annotation will zoom in to show the cluster, tapping on the other annotations will bring up a callout with some detail information.

My problem is now related to the callout of the single location annotation. When I tap on the annotation and the annotation callout can be shown without changing the region of the map view (which is done by the map view implicitly) everything is fine. But when I tap on it when it is next to the bounds of the map view and the map view has to change its region to show the callout without cutting it, the callout disappears right after it appeared. In the debug log this message appears:

Expected window when dismissing popover view in order to set rasterization scale. Using mainScreen scale instead. popoverView = <_UIPopoverView: 0xa989550; frame = (-73 -57; 146 57); layer = <CALayer: 0x26ec06e0>>

The other problem is that when I opened a callout of an annotation and then drag the map view and change its region (no zooming) then the callout is closed.

I have no idea why this happens and I couldn't find anything on the web. I guess that this is related to the cluster controller (the code I use is commented), because when I add the annotations without clustering everything works fine.

A screenshot and the code can be found below. Maybe somebody has an idea and could help me out.

screen shot 2014-03-18 at 09 42 46

#import "StationsMapViewController.h"
#import <CCHMapClusterController.h>
#import <CCHMapClusterAnnotation.h>
#import "Station.h"
#import <MKMapViewUtil.h>
#import "StationAnnotation.h"
#import "StationsContainerViewController.h"


@interface StationsMapViewController () <MKMapViewDelegate>

@property (strong, nonatomic) NSArray *stations;
@property (strong, nonatomic) CLLocation *currentLocation;
@property (strong, nonatomic) CCHMapClusterController *mapClusterController;

@end


@implementation StationsMapViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.mapClusterController = [[CCHMapClusterController alloc] initWithMapView:self.mapView];
    self.mapClusterController.cellSize = 100;
    self.mapClusterController.reuseExistingClusterAnnotations = NO;
}


- (void)showStations:(NSArray *)stations withCurrentLocation:(CLLocation *)currentLocation {
    self.stations = stations;
    self.currentLocation = currentLocation;

    [self.mapClusterController removeAnnotations:self.mapClusterController.annotations.allObjects withCompletionHandler:nil];
//  [self.mapView removeAnnotations:self.mapView.annotations];

    if (self.stations.count > 0) {
        NSMutableArray *annotations = [NSMutableArray arrayWithCapacity:stations.count];

        for (Station *station in stations) {
            StationAnnotation *annotation = [[StationAnnotation alloc] init];
            annotation.station = station;
            [annotations addObject:annotation];
        }

        [self.mapClusterController addAnnotations:annotations withCompletionHandler:NULL];
//      [self.mapView addAnnotations:annotations];

        MKCoordinateRegion region = [MKMapViewUtil regionThatFitsAnnotations:annotations];
        region = [self.mapView regionThatFits:region];
        [self.mapView setRegion:region animated:YES];
    }
}


- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
    if ([annotation isKindOfClass:CCHMapClusterAnnotation.class]) {
//  if ([annotation isKindOfClass:StationAnnotation.class]) {
        CCHMapClusterAnnotation *clusterAnnotation = (CCHMapClusterAnnotation *)annotation;

        if (clusterAnnotation.isCluster) {
            static NSString *clusterAnnotationViewIdentifier = @"ClusterAnnotationView";
            static NSInteger labelTag = 10000;
            MKAnnotationView *annotationView = (MKAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier:clusterAnnotationViewIdentifier];

            if (annotationView == nil) {
                UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
                label.tag = labelTag;
                label.textAlignment = NSTextAlignmentCenter;
                label.font = [UIFont boldSystemFontOfSize:16];
                label.backgroundColor = [UIColor clearColor];

                annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:clusterAnnotationViewIdentifier];
                annotationView.canShowCallout = NO;
                [annotationView addSubview:label];
                annotationView.centerOffset = CGPointMake(-20, -20);
                annotationView.image = [UIImage imageNamed:@"clusterAnnotationImage"];
            }
            else {
                annotationView.annotation = annotation;
            }

            ((UILabel *) [annotationView viewWithTag:labelTag]).text = [NSString stringWithFormat:@"%lu", (unsigned long)clusterAnnotation.annotations.count];

            return annotationView;
        }
        else {
            static NSString *stationAnnotationViewIdentifier = @"StationAnnotationView";
            MKPinAnnotationView *annotationView = (MKPinAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier:stationAnnotationViewIdentifier];

            if (annotationView == nil) {
                annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:stationAnnotationViewIdentifier];
                annotationView.pinColor = MKPinAnnotationColorRed;
                annotationView.animatesDrop = NO;
                annotationView.canShowCallout = YES;
                annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
            }
            else {
                annotationView.annotation = annotation;
            }

            StationAnnotation *stationAnnotation = [[clusterAnnotation.annotations objectEnumerator] nextObject];
            clusterAnnotation.title = stationAnnotation.title;
            clusterAnnotation.subtitle = stationAnnotation.subtitle;

            return annotationView;
        }
    }

    return nil;
}


- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
    CCHMapClusterAnnotation *clusterAnnotation = (CCHMapClusterAnnotation *)view.annotation;
    if (clusterAnnotation.isOneLocation) {
        StationAnnotation *stationAnnotation = [[clusterAnnotation.annotations objectEnumerator] nextObject];
        [self.stationsContainerViewController showStationDetailWithStation:stationAnnotation.station];
    }
}


- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
    if ([view.annotation isKindOfClass:CCHMapClusterAnnotation.class]) {
        CCHMapClusterAnnotation *clusterAnnotation = (CCHMapClusterAnnotation *) view.annotation;

        if (clusterAnnotation.isCluster) {
            CCHMapClusterAnnotation *clusterAnnotation = (CCHMapClusterAnnotation *) view.annotation;
            MKMapRect mapRect = [clusterAnnotation mapRect];
            UIEdgeInsets edgeInsets = UIEdgeInsetsMake(90, 25, 80, 25);
            [mapView setVisibleMapRect:mapRect edgePadding:edgeInsets animated:YES];
        }
    }
}

@end

Crash: [__NSPlaceholderSet initWithObjects:count:]: attempt to insert nil

Hello

This is the case when the data is already loaded completely and the user quickly switches to map portions of coordinates. For example, the countries

How to reproduce:
1 "CCHMapClusterController Example iOS" - DataReader.m
method "dispatchAnnotations" - comment out "[NSThread sleepForTimeInterval: DELAY_BETWEEN_BATCHES]"
2 frequently and quickly press the "reset"

CCHMapClusterController Example iOS[4322:60b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[__NSPlaceholderSet initWithObjects:count:]: attempt to insert nil object from objects[9972]'

sometimes falls out of memory

[CCHMapViewDelegateProxy mapView:didUpdateUserLocation:]: unrecognized selector sent to instance

With version 1.6.4 we have started to see this crash in our logs. Fortunately it happens very rarely. We haven't been able to reproduce it.

-[CCHMapViewDelegateProxy mapView:didUpdateUserLocation:]: unrecognized selector sent to instance 0x17baa680

0 CoreFoundation 0x2c529e3f + 126
1 libobjc.A.dylib 0x39c16c8b objc_exception_throw + 38
2 CoreFoundation 0x2c52f189 + 0
3 CoreFoundation 0x2c52d0a7 + 714
4 CoreFoundation 0x2c45f208 _CF_forwarding_prep_0 + 24
5 MapKit 0x2dc4eef3 redacted + 2130
6 CoreFoundation 0x2c4657f9 + 204
7 MapKit 0x2dc14fed redacted + 76
8 MapKit 0x2dc14c79 redacted + 1248
9 MapKit 0x2dc145bd redacted + 608
10 MapKit 0x2dc1434f redacted + 62
11 MapKit 0x2dc140f7 redacted + 302
12 CoreLocation 0x2cbe7e65 CLClientGetCapabilities + 21688
13 CoreLocation 0x2cbe3d0b CLClientGetCapabilities + 4958
14 CoreLocation 0x2cbddaf7 CLClientInvalidate + 966
15 CoreFoundation 0x2c4f05b5 + 12
16 CoreFoundation 0x2c4ef879 + 216
17 CoreFoundation 0x2c4ee3b3 + 1714
18 CoreFoundation 0x2c43c621 CFRunLoopRunSpecific + 476
19 CoreFoundation 0x2c43c433 CFRunLoopRunInMode + 106
20 GraphicsServices 0x337eb0a9 GSEventRunModal + 136
21 UIKit 0x2fa27359 UIApplicationMain + 1440
22 Rabble 0x00092169 0x8a000 + 33129
23 libdyld.dylib 0x3a196aaf + 2

Disabling clusterisation

Hello.
First of all, thanks for nice framework, working for me like a charm.

I have a question. I am moving a camera manually (some animation), and when I moving it, framework trying to make clusterisation every frame (I think it;s because of setCamera calls). Is there any way to manually stop and then resume clusterisation?

It will be nice if I'll can stop clusterisation, make animation, and the restart it.

Thanks for your time, Karen.

Updating Annotation Views when zomming in and out

I am having kind of the same issue as in #23 .
If an annotation isOneLocation I'd like to show an image instead of the default MKAnnotationView pin. I do that by simple setting an image on the annotationView.
But... if the location is not one location, I want to show a complete custom AnnotationView. So I subclassed MKAnnotationView and overwrote the drawRect method... (It's just a circle with a number in it ;-) )

How can I now tell CCHMapClusterControllerthat he needs to go and get a new view for that annotation if the annotations changes it's isOneLocation property?

I already found mapClusterController:willReuseMapClusterAnnotation: but I can't change the view class that's being used for the annotation, right?

The regionSpan can change slightly

Hi Claus,

I've noticed the clusters to rearrange when I programmtically change the region of the map. When the user is moving the map by hand, everything is fine and the clusters stay the same. But whenever I use setCenterCoordinate:animated: or setRegion:animated:, the annotation clusters rearrange themselves. I've noticed that the CCHMapClusterController stores the MKCoordinateSpan right before the region is changed, and compares it to the new span afterwards.
In the documentation of setCenterCoordinate:animated: Apple promises:

Changing the center coordinate centers the map on the
new coordinate without changing the current zoom level.

This is true from a human point of view. At least I cannot see the map zoom in. But the span value changes slightly. I've created a branch here to illustrate the issue: https://github.com/plu/CCHMapClusterController/compare/regionSpanBeforeChange

There are three commits. If you reset to the first one (5451b4f) and tap on any of the annotations, you'll see that while it's being centered, the clusters are rearranged. The other two commits are not meant to be a proper fix. Just to illustrate the difference.

Do you have any idea how to properly fix this?

Best regards,
plu

updateAnnotationsWithCompletionHandler called twice

Because I add annotations when the region changes I end up having updateAnnotationsWithCompletionHandler called twice.

Perhaps we could fix this by providing a setting like CCHMapClusterController.shouldUpdateOnRegionDidChange with a default value of YES.

I could then skip updateAnnotationsWithCompletionHandler in CCHMapClusterController's mapView:regionDidChangeAnimated:

Issues in: Zooming in to a cluster + Centering the map without changing the zoom level

Hi,

I am facing 2 issues which are mentioned below:

  1. While using the code to "Centring the map without changing the zoom level"
    which is as below:
    MKMapPoint point = MKMapPointForCoordinate(view.annotation.coordinate);
    MKMapRect rect = [mapView visibleMapRect];
    rect.origin.x = point.x - rect.size.width * 0.5;
    rect.origin.y = point.y - rect.size.height * 0.5;
    [mapView setVisibleMapRect:rect animated:YES];

Map view zooms out [earlier zoom level is around 17 and after running above lines of code zoom level is 16], due to which the annotations are clustered again and "didDeselectAnnotationView" is called. Due to this, user is never able to view these annotations, every-time the view is zoomed out. If user try to manually zoom in again, then again the view is zoomed out.

  1. While using the code to "Zooming in to a cluster"
    using these lines of code:
    if ([view.annotation isKindOfClass:CCHMapClusterAnnotation.class]) {
    CCHMapClusterAnnotation *clusterAnnotation = (CCHMapClusterAnnotation *)view.annotation;
    MKMapRect mapRect = [clusterAnnotation mapRect];
    UIEdgeInsets edgeInsets = UIEdgeInsetsMake(20, 20, 20, 20);
    [mapView setVisibleMapRect:mapRect edgePadding:edgeInsets animated:YES];
    }

It works perfectly till zoom level reached around 17, but after that i again want to zoom further, need zoom level of 18.5 approx., but it does not allow to zoom. Rather, it keeps on showing the same location again and again.

My need is that, if the annotation is clustered, then zoom further till one unique location is found. And once that unique location is found, show the annotation view.

Sample code is here (includes the code for both the above mentioned issues):

  • (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(ClusterAnnotationView *)view {

    if ([view.annotation isKindOfClass:[MKUserLocation class]]) {
    }
    else{

    CCHMapClusterAnnotation *clusterAnnotation = view.annotation;
    
    if (clusterAnnotation.isUniqueLocation == FALSE){
        CCHMapClusterAnnotation *clusterAnnotation = (CCHMapClusterAnnotation *)view.annotation;
        MKMapRect mapRect = [clusterAnnotation mapRect];
         CGFloat val = 10;
        UIEdgeInsets edgeInsets = UIEdgeInsetsMake(val, val, val, val);
        [mapView setVisibleMapRect:mapRect edgePadding:edgeInsets animated:YES];
    }
    else{
        // mapView.centerCoordinate = view.annotation.coordinate;
        MKMapPoint point = MKMapPointForCoordinate(view.annotation.coordinate);
        MKMapRect rect = [mapView visibleMapRect];
        rect.origin.x = point.x - rect.size.width * 0.5;
        rect.origin.y = point.y - rect.size.height * 0.5;
        [mapView setVisibleMapRect:rect animated:YES];
    
      [customCalloutView setTag:kTag_CustomCalloutView];
        [view addSubview:customCalloutView];
    
       [customCalloutView setCenter:CGPointMake(view.bounds.size.width * 0.5f, -customCalloutView.frame.size.height * 0.5f)];
    
        NSArray *myArray = [clusterAnnotation.annotations allObjects];   
    
        NSMutableArray *tempArr = [[NSMutableArray alloc] init];           
    
        for (int _i = 0; _i < [myArray count]; _i++){                
            CustomPointAnnotation *pointAnnotation = [myArray objectAtIndex:_i];
    
            [tempArr addObject:searchResultsArray[pointAnnotation.tag]];
    
        }            
        annotationzArray = nil;
        annotationzArray = tempArr;
        [annotationzTV reloadData];
    }
    

    }
    }

Please respond asap.

Thanks in advance!

cluster is not selectable sometimes

Hey,
i have a small issue that i would love if you can help me with.
when i press a cluster i push another view controller but when i get back to the map i am unable to select that cluster again unless i pinch the map a little to zoom in or out.
it just ignores my touches till i do that.
do you have any idea what might be causing that?

Remove all annotations not working properly

Hello guys,

I'm having some trouble using removeAnnotations:withCompletionHandler when updating my annotations after adding them to the map.

The problem is that after updating the coordinate of my annotations, some of them are never removed from the map. From what I found ( guess ), CCHMapTreeNodeRemoveData(_root, data)) is in charge of removing the node from the map, internally it calls CCHMapTreeBoundingBoxContainsData to see if the data is inside the bounding box of the node. I thinks the problem here is that the bounding box of the tree is outdated due to the update in the coordinate.

I'm using Core Data with my application for backing up my annotations. Map Kit uses KVO to observe the coordinate property of the annotation and update the position if it changes, I think CCHMapClusterController doesn't have the same behaviour.

Let me know if anything of what I said makes sense.

Thanks and keep up the good work.

CompletionHandler block being called before completion

When I try to addAnnotations:withCompletionHandler: the completion block is being called before all annotations are added in the map.

I have a method when I try to recenter the map region based on its annotations and this method must be called after all annotations get pinned.

I believe that this is a bug. If not, the parameter name should be changed because completionHandler gives the understanding that this is called after everything is done.

Debug grid not displaying correctly around the 180th meridian

To reproduce:

  • Enable debug switch in settings
  • Scroll to 180th meridian

Result: debug grid doesn't get displayed correctly.

This used to work by subtracting MKMapSizeWorld.width in updateDebugPolygonsInGridMapRect:withCellMapSize:, but broke in iOS 7.1.

problem with selectAnnotation

Ive implemented the MkMapViewDelegate to get called when an annotation is selected; on my code I want to zoom in the annotation, I call this code

- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
        [_mapClusterController selectAnnotation:view.annotation
           andZoomToRegionWithLatitudinalMeters:1000.0f
                             longitudinalMeters:1000.0f];
}

then there is a bug, the map si zoomed correctly but then it moves to a region with center 0,0
I found the problem to be in here

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
...
        if (self.annotationToSelect) {
            // Map has zoomed to selected annotation; search for cluster annotation that contains this annotation
            CCHMapClusterAnnotation *mapClusterAnnotation = CCHMapClusterControllerClusterAnnotationForAnnotation(self.mapView, self.annotationToSelect, mapView.visibleMapRect);
...

at this point for some reason the mapClusterAnnotation is nil , the test that check if the map view centerCoordinate is the same will fail and then map is moved on the west coast of Africa :-)

                    [self.mapView setCenterCoordinate:mapClusterAnnotation.coordinate animated:NO];

At the moment my work around is to setVisibleMapRect by hand but this means that when the map is zoomed in the cluster annotation for that region may not be there anymore (which may also explain the reason I've the bug, maybe i zoom too much close)

Different trees

Hey mate,

it is possible to add 2 or more different trees?

The thing is, I have got more then 1 kind of Annotations with different pin color and would like to separate this pins onto the map.

Cheers,

Eike

"completionHandler Called when the clustering finished updating" contract advertised in the API header is not honoured

Both addAnnotations:withCompletionHandler: and removeAnnotations:withCompletionHandler: take a completion handler, but that's going to be called before the cluster actually finished updating its annotation view. That's because mapClusterController:willReuseMapClusterAnnotation:, which presumably updates the annotation view, gets dispatch_async(ed) on the main queue, and might be executed after the completionBlock of CCHMapClusterOperation.

This means that the clustering may still be changing, at least visually, after the completion handlers get called.

can only touch centre of cluster to invoke didselectAnnotationView

this is an example of how i setup my annotationView in viewForAnnotation
my problem is that i have to exactly touch the centre of the annotationView to actually select it.
i tried setting all the subviews UserInteractionEnabled property to YES but it didn't make any difference.

MKAnnotationView *annotationView = (MKAnnotationView *) [mapView dequeueReusableAnnotationViewWithIdentifier:kPictureAnnotationIdentifier];
if (annotationView == nil) {
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:kPictureAnnotationIdentifier];
UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"whiteBackground"]];
backgroundImageView.center = annotationView.center;
[annotationView addSubview:backgroundImageView];
UIImageView *imageView = [[UIImageView alloc] initWithImage:pictureAnnotation.thumbnailImage];
imageView.center = annotationView.center;
[imageView setTag:2];
[annotationView addSubview:imageView];
annotationView.enabled = YES;
[annotationView sendSubviewToBack:backgroundImageView];
}else {
annotationView.annotation = annotation;
UIImageView *imageView = (UIImageView *)[annotationView viewWithTag:2];
[imageView setImage:pictureAnnotation.thumbnailImage];
[annotationView bringSubviewToFront:imageView];
}

as always i truly appreciate your support

Compiling on Xcode 6 (Beta 3)

Xcode 6 seems to have an issue automatically synthesizing properties that have a custom setter method. Therefore, CCHMapClusterOperation will not compile. This easily fixed by adding

@synthesize executing = _executing;
@synthesize finished = _finished;

to the @implimentation block. Just wanted to make you aware.

Clustering count issue

I might be overlooking where to do this but I am querying for objects from Parse and populating the map. I have pretty much everything integrated but I want a user to be able to click on a cluster icon and then it displays the objects that are in that cluster. what is the best way I should approach this? I read that it might not be possible to display individual annotations? I tried changing the maxZoomLevel but didn't have any luck. Would there be a a way I could get the objects of that cluster to display them elsewhere? Any help would be appreciated.

Thank you
-Blake

view for annotation sometimes does not get called for the cluster when i zoom sometimes

i hope i can explain this simply. here goes.
i have a cluster with 9 annotations. ( i show the number 9 on the cluster annotation)
when i zoom in a little another annotation pops up on its own and the cluster ( but now the cluster count should be 8 but it stays at 9) when i zoom in again the count is updated to 8.

if i zoom in a lot till i can see all the separate annotations and then zoom out again fully i don't see the count 9 straight away. however i see a random annotation ( either a number of one of the smaller clusters or on of the annotations on their own) if i move away from this location on the map and then come back i see the number 9 again as viewForAnnotation gets called normally.
do you get what i mean?
is it something on my side of the code?

thank you very much for your support

MaxZoomLevel not working

Hello.
Can you help me please, I'm using this code for creating the clusterer.

if (self.mapClusterController == nil)
{
    self.mapClusterController = [[CCHMapClusterController alloc] initWithMapView: map];
    self.mapClusterController.delegate = self;

    self.mapClusterController.maxZoomLevelForClustering = 15;
    self.mapClusterController.cellSize = 10;
    self.mapClusterController.marginFactor = 0.3;

    self.mapClusterer = [[CCHNearCenterMapClusterer alloc] init];
    self.mapClusterController.clusterer = self.mapClusterer;

    self.mapAnimator = [[CCHFadeInOutMapAnimator alloc] init];
    self.mapClusterController.animator = self.mapAnimator;
}
[self.mapClusterController removeAnnotations: annotations withCompletionHandler: NULL];
[self.mapClusterController addAnnotations: annotations withCompletionHandler: NULL];

However clustering is not disabling even when zoomlevel is 17 or 18.
I getting zoom level from clusterer (for debug) so it knows about current zoom level.
What I'n doing wrong?

MapView didSelectAnnotationView is not called

Hello!

I don't know why, but running the Example Project, the delegate method "didSelectAnnotationView" is called, but in my project not.

I've implemented using example project as guide.
Property "canShowCallout" is "YES".

Is there something that I need to check?

Color of Annotations

Hello, is there any simple way to change the annotation color on the map? Would I just have to extract the images and change them manually? Would you by chance have the sizes of them? Any help would be appreciated. Thank You

Crash in [CCHMapClusterController updateAnnotationsWithCompletionHandler]

Hi @choefele,

We have encountered a crash that happens for more than a few users of our app.
Crash occurs in CCHMapClusterController updateAnnotationsWithCompletionHandler, at line 219.
See the crashlog from Crashlytics.
We are using the version 1.5.0 via CocoaPods.
The exception:

Fatal Exception: NSInvalidArgumentException
*** -[__NSSetM addObject:]: object cannot be nil

The line that causes the crash

NSSet *annotationsBeforeAsSet = CCHMapClusterControllerClusterAnnotationsForAnnotations(self.mapView.annotations, self);

My opinion is that the crash is caused by self.mapView.annotations being executed on the background queue.

I noticed that in the most recent master branch, this code has been refactored so that the call to [MKMapView annotations] is made in [CCHMapClusterOperation initWith...]. The init method are always called on main thread, as the updateAnnotationsWithCompletionHandler method is called on the main thread and this is the only place where CCHMapClusterOperation objects are created.

Q1: Does this crash/crashlog tell you anything? Do you have more insight into this?
Q2: If we can assume that was the cause of the crash and it's fixed on the master branch, could you release a new version for CocoaPods?

Thanks,
Bogdan

CCHMapClusterAnnotation isEqual: and hash

I do not add all of the annotations at once. I add new annotations every time I go to a new region. For this reason I add the same annotation (different objects) multiple times.

In order for the following code in CCHMapClusterController to work…

    // Figure out difference between new and old clusters
    NSMutableSet *annotationsBefore = [NSMutableSet setWithArray:_mapView.annotations];
    [annotationsBefore removeObject:[_mapView userLocation]];
    NSMutableSet *annotationsToKeep = [NSMutableSet setWithSet:annotationsBefore];
    [annotationsToKeep intersectSet:clusters];
    NSMutableSet *annotationsToAddAsSet = [NSMutableSet setWithSet:clusters];
    [annotationsToAddAsSet minusSet:annotationsToKeep];
    NSArray *annotationsToAdd = [annotationsToAddAsSet allObjects];
    NSMutableSet *annotationsToRemoveAsSet = [NSMutableSet setWithSet:annotationsBefore];
    [annotationsToRemoveAsSet minusSet:clusters];
    NSArray *annotationsToRemove = [annotationsToRemoveAsSet allObjects];

CCHMapClusterAnnotation needs custom isEqual: and hash methods. I added the following less than perfect implementations.

- (BOOL)isEqual:(id)object
{
    if ([[object class] isSubclassOfClass:[CCHMapClusterAnnotation class]])
    {
        CCHMapClusterAnnotation *other = (CCHMapClusterAnnotation *)object;
        if (other.coordinate.latitude == self.coordinate.latitude
            && other.coordinate.longitude == self.coordinate.longitude) return YES;
    }
    return NO;
}

- (NSUInteger)hash
{
    return @(self.coordinate.longitude).hash ^ @(self.coordinate.latitude).hash;
}

Without these, each annotation is removed and added again when I pan the map.

didSelectAnnotationView not call when clicking on my ClusterAnnotationView

Hi,

I have some trouble to detect click on my AnnotationView.
I write the following didSelectAnnotationView :

capture decran 2014-06-04 a 18 52 38

Unfortunately, this method is never called when I click on my AnnotationVIew, except if the following method returns a NSString :

capture decran 2014-06-04 a 18 52 58

So, this will displayed a bubble with a space but I don't need any bubble and title.
Do you have any idea what is the issue please ?

Question - animation

Hi,
I'd like to have my pins moving from cluster position to their own position and viceversa (like the photo application). Unfortunately I don't see how I could implement this with the map animator protocol, for instance how can I get the "parent" location when an annotation is moved in/out from a cluster ?
thanks

Question: Callout with CalloutAccessoryView

Would it be possible to only add rightCalloutAccessoryView & leftCalloutAccessoryView to the annotations which is not clustered? Right now, if I add the AccessoryViews it is also displayed on the clustered annotations.
How would I manage to only show the accessoryViews on the nonclustered annotations / one location annotations?

I have tried the following in the mapView:(MKMapView*)mapView viewForAnnotation:(id)annotation method, but it does not work:

if ([annotation isKindOfClass:[MOMapClusterAnnotation class]]) {

    annotationView.canShowCallout = YES;
    annotationView.count = [(MOMapClusterAnnotation*)annotation annotations].count;
    annotationView.innerCircleFillColor = [UIColor myOrderThemeColor];


    if ([(CCHMapClusterAnnotation*)annotation annotations].count == 1 && [(MOMapClusterAnnotation*)annotation isOneLocation] ) {


        annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; 
        annotationView.leftCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure]; 
    }

}

Thank you for the help in advance :-)

Question

Thanks for this great library.

i just wanted to ask something. In my scenario i show pins on a map which represent images. However someone might have shot several images on a single location. This means that even on the max zoom i would show a cluster instead of individual pins.
Is there a way to know the pins inside each cluster?
For example long tap the cluster to NSLog which objects are inside.
I can then use this info and show a pop up with the thumbs of the images inside that cluster.

Any help would be great
Thanks again
Konstantinos

Need to display a selected annotation with different icon

It would be really nice if there was a way to solve this in this otherwise fantastic project. The problem is that when user selects an annotation I need it to change its icon and also the previous selected annotation needs to change its icon back to what it was before.
The best thing would be if it didn't become clustered so it always is visible.

In mapView:viewForAnnotation I've setup a check to see if annotation is selected and give it the right icon. It works for the newly selected annotation, but the previous selected doesn't update.

I tried removing it and adding it in didSelectAnnotationView but it doesn't work all the time:

- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView   *)view {
    CCHMapClusterAnnotation *anno = view.annotation;

    [self.mapClusterController removeAnnotations:@[self.previousSelectedAnnotation] withCompletionHandler:^{
        [self.mapClusterController addAnnotations:@[self.previousSelectedAnnotation] withCompletionHandler:nil];
    }];
}

I'm thinking maybe there could be two clusterControllers where only the selected annotation could be in one of them. Removing annotations from one and add it to another.. is that a good idea?

mapClusterController is always nil in mapClusterController:titleForMapClusterAnnotation:

I'm working on a map and use multiple cluster controllers because I have different types of annotations. I'm using the mapClusterController:titleForMapClusterAnnotation: delegate method to provide a title to my cluster annotations.
Problem is the mapClusterController variable is always nil : https://github.com/choefele/CCHMapClusterController/blob/master/CCHMapClusterController/CCHMapClusterAnnotation.m#L33-L49

I'd be more than happy to provide a quick fix for this, but maybe there is a reason why it was made this way?

Problems when zooming out after zooming in. Single annotations show cluster-annotation callouts.

Thanks for a great lib.

I am having trouble with the annotation callouts and I do not know what I am doing wrong.
When I enter my view controllers view, the annotations are clustered perfectly.
When i then zoom in on my annotations they are declustered as expected.

However, when i zoom back out and the annotations starts to group up to clusters again, some clusters have the image of a single annotation. The same thing goes for their callouts. They have the titles and subtitles of my clustered annotations, but they have the disclosure button which i have only assigned to single, unclustered annotations.

This is how i initialize my cluster controller:
...

// viewDidLoad

    self.mapClusterController = nil;
    self.mapClusterController = [[CCHMapClusterController alloc]     initWithMapView:self.mapView];
    self.mapClusterController.delegate = self;
    self.mapClusterController.cellSize = 25;
    self.mapClusterController.marginFactor = 0.4;

//
...

This is how i populate the controller with my own custom annotations:
//...

[self.mapClusterController removeAnnotations:[self.mapClusterController.annotations     allObjects] withCompletionHandler:nil];
    NSMutableArray *arrayWithAnnotations = [[NSMutableArray alloc] init];
    FFMapAnnotation *annotation;
    for(FFPlace *place in self.searchResult){
        annotation = [[FFMapAnnotation alloc] init];
        annotation.title = place.placeName;
        annotation.coordinate = CLLocationCoordinate2DMake(place.placeLatitude,     place.placeLongitude);
        annotation.place = place;
        annotation.subtitle = place.placeAddress;
        [arrayWithAnnotations addObject:annotation];
    }
    [self.mapClusterController addAnnotations:arrayWithAnnotations     withCompletionHandler:nil];

//...

Now, I do believe that these two methods work correctly.
I imagine that the problem lies within the viewForAnnotation method.

This is currently how it looks:

-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id     <MKAnnotation>)annotation
{
    MKAnnotationView *annotationView;

if ([annotation isKindOfClass:CCHMapClusterAnnotation.class]) {
    static NSString *identifier = @"clusterAnnotation";

    annotationView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
    if (annotationView) {
        annotationView.annotation = annotation;
    } else {
        annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
        annotationView.canShowCallout = YES;
    }

    CCHMapClusterAnnotation *clusterAnnotation = (CCHMapClusterAnnotation *)annotation;
    clusterAnnotation.delegate = self;
    if(!clusterAnnotation.isCluster){
        FFMapAnnotation *annot2 = (FFMapAnnotation*)clusterAnnotation.annotations.allObjects[0];
        annotationView.image = [UIImage imageNamed:[DefinedCategories getCategoryInformationForID:annot2.place.placeMainCategoryID].mapImage];
        annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeContactAdd];
        annotationView.rightCalloutAccessoryView.tag = -1;
    }else {
        return nil;
    }

}

return annotationView;

}
// the return nil at the end makes the annotation view a regular MKPinAnnotationView, which i use to visually represent my clusters.

Finally, the two delegate methods for cluster title and subtitle looks like this:

- (NSString *)mapClusterController:(CCHMapClusterController *)mapClusterController     titleForMapClusterAnnotation:(CCHMapClusterAnnotation *)mapClusterAnnotation
{
    NSString *title;
    if(mapClusterAnnotation.annotations.count > 1){
        title = [NSString stringWithFormat:@"%ld %@", (unsigned long)      mapClusterAnnotation.annotations.count, [AppDelegate get:@"PLACES"alter:nil]];
    } else{
        FFMapAnnotation *annotation =  mapClusterAnnotation.annotations.allObjects[0];
        return annotation.title;
    }
    return title;
}    

- (NSString *)mapClusterController:(CCHMapClusterController *)mapClusterController     subtitleForMapClusterAnnotation:(CCHMapClusterAnnotation *)mapClusterAnnotation
{
    NSString *title;
    if(mapClusterAnnotation.annotations.count > 1){
        title = [AppDelegate get:@"ZOOM_FURTHER"alter:nil];
    } else{
        FFMapAnnotation *annotation = mapClusterAnnotation.annotations.allObjects[0];
        return annotation.subtitle;
    }
    return title;
}

What i want :

pastedgraphic-3
pastedgraphic-2

What sometimes happens:
pastedgraphic-1

Am I missing something vital in the delegate methods? I spent all day debugging this.

Thank you very much for this awesome lib.

Implement minimum cluster size

If cluster size is less than this size, display individual markers.

Similar to MIN_CLUSTER_SIZE in Google's Android Maps Utils library.

Has to work with annotations at the same location (which will still be clustered).

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.