![]() |
OCMapView 1.0
Simple and easy to use clustering mapView.
|
00001 // 00002 // OCMapView.m 00003 // openClusterMapView 00004 // 00005 // Created by Botond Kis on 14.07.11. 00006 // 00007 00008 #import "OCMapView.h" 00009 00010 @interface OCMapView (private) 00011 - (void)initSetUp; 00012 @end 00013 00014 @implementation OCMapView 00015 @synthesize clusteringEnabled; 00016 @synthesize annotationsToIgnore; 00017 @synthesize clusteringMethod; 00018 @synthesize clusterSize; 00019 @synthesize clusterByGroupTag; 00020 @synthesize minLongitudeDeltaToCluster; 00021 00022 - (id)init 00023 { 00024 self = [super init]; 00025 if (self) { 00026 // call acutal constructor 00027 [self initSetUp]; 00028 } 00029 00030 return self; 00031 } 00032 00033 - (id)initWithCoder:(NSCoder *)aDecoder{ 00034 self = [super initWithCoder:aDecoder]; 00035 if (self) { 00036 // call acutal constructor 00037 [self initSetUp]; 00038 } 00039 return self; 00040 } 00041 00042 - (void)initSetUp{ 00043 allAnnotations = [[NSMutableSet alloc] init]; 00044 annotationsToIgnore = [[NSMutableSet alloc] init]; 00045 clusteringMethod = OCClusteringMethodBubble; 00046 clusterSize = 0.2; 00047 minLongitudeDeltaToCluster = 0.0; 00048 clusteringEnabled = YES; 00049 clusterByGroupTag = NO; 00050 backgroundClusterQueue = dispatch_queue_create("com.OCMapView.clustering", NULL); 00051 } 00052 00053 - (void)dealloc{ 00054 [allAnnotations release]; 00055 [annotationsToIgnore release]; 00056 dispatch_release(backgroundClusterQueue); 00057 00058 [super dealloc]; 00059 } 00060 00061 // ====================================== 00062 #pragma mark MKMapView implementation 00063 00064 - (void)addAnnotation:(id < MKAnnotation >)annotation{ 00065 [allAnnotations addObject:annotation]; 00066 [self doClustering]; 00067 } 00068 00069 - (void)addAnnotations:(NSArray *)annotations{ 00070 [allAnnotations addObjectsFromArray:annotations]; 00071 [self doClustering]; 00072 } 00073 00074 - (void)removeAnnotation:(id < MKAnnotation >)annotation{ 00075 [allAnnotations removeObject:annotation]; 00076 [self doClustering]; 00077 } 00078 00079 - (void)removeAnnotations:(NSArray *)annotations{ 00080 [annotations retain]; 00081 for (id<MKAnnotation> annotation in annotations) { 00082 [allAnnotations removeObject:annotation]; 00083 } 00084 [annotations release]; 00085 [self doClustering]; 00086 } 00087 00088 00089 // ====================================== 00090 #pragma mark - Properties 00091 // 00092 // Returns, like the original method, 00093 // all annotations in the map unclustered. 00094 - (NSArray *)annotations{ 00095 return [allAnnotations allObjects]; 00096 } 00097 00098 // 00099 // Returns all annotations which are actually displayed on the map. (clusters) 00100 - (NSArray *)displayedAnnotations{ 00101 return super.annotations; 00102 } 00103 00104 // 00105 // enable or disable clustering 00106 - (void)setClusteringEnabled:(BOOL)enabled{ 00107 clusteringEnabled = enabled; 00108 [self doClustering]; 00109 } 00110 00111 // ====================================== 00112 #pragma mark - Clustering 00113 00114 - (void)doClustering{ 00115 00116 // Remove the annotation which should be ignored 00117 NSMutableArray *bufferArray = [[NSMutableArray alloc] initWithArray:[allAnnotations allObjects]]; 00118 [bufferArray removeObjectsInArray:[annotationsToIgnore allObjects]]; 00119 NSMutableArray *annotationsToCluster = [[NSMutableArray alloc] initWithArray:[self filterAnnotationsForVisibleMap:bufferArray]]; 00120 [bufferArray release]; 00121 00122 //calculate cluster radius 00123 CLLocationDistance clusterRadius = self.region.span.longitudeDelta * clusterSize; 00124 00125 // Do clustering 00126 NSArray *clusteredAnnotations; 00127 00128 // Check if clustering is enabled and map is above the minZoom 00129 if (clusteringEnabled && (self.region.span.longitudeDelta > minLongitudeDeltaToCluster)) { 00130 00131 // switch to selected algoritm 00132 switch (clusteringMethod) { 00133 case OCClusteringMethodBubble:{ 00134 clusteredAnnotations = [[NSArray alloc] initWithArray:[OCAlgorithms bubbleClusteringWithAnnotations:annotationsToCluster andClusterRadius:clusterRadius grouped:self.clusterByGroupTag]]; 00135 break; 00136 } 00137 case OCClusteringMethodGrid:{ 00138 clusteredAnnotations =[[NSArray alloc] initWithArray:[OCAlgorithms gridClusteringWithAnnotations:annotationsToCluster andClusterRect:MKCoordinateSpanMake(clusterRadius, clusterRadius) grouped:self.clusterByGroupTag]]; 00139 break; 00140 } 00141 default:{ 00142 clusteredAnnotations = [annotationsToCluster retain]; 00143 break; 00144 } 00145 } 00146 } 00147 // pass through without when not 00148 else{ 00149 clusteredAnnotations = [annotationsToCluster retain]; 00150 } 00151 00152 // Clear map but leave Userlcoation 00153 NSMutableArray *annotationsToRemove = [[NSMutableArray alloc] initWithArray:self.displayedAnnotations]; 00154 [annotationsToRemove removeObject:self.userLocation]; 00155 00156 // add clustered and ignored annotations to map 00157 [super addAnnotations: clusteredAnnotations]; 00158 [super addAnnotations: [annotationsToIgnore allObjects]]; 00159 00160 // fix for flickering 00161 [annotationsToRemove removeObjectsInArray: clusteredAnnotations]; 00162 [super removeAnnotations:annotationsToRemove]; 00163 00164 // memory 00165 [clusteredAnnotations release]; 00166 [annotationsToCluster release]; 00167 [annotationsToRemove release]; 00168 } 00169 00170 // ====================================== 00171 #pragma mark - Helpers 00172 00173 - (NSArray *)filterAnnotationsForVisibleMap:(NSArray *)annotationsToFilter{ 00174 // return array 00175 NSMutableArray *filteredAnnotations = [[NSMutableArray alloc] initWithCapacity:[annotationsToFilter count]]; 00176 00177 // border calculation 00178 CLLocationDistance a = self.region.span.latitudeDelta/2.0; 00179 CLLocationDistance b = self.region.span.longitudeDelta /2.0; 00180 CLLocationDistance radius = sqrt(a*a + b*b); 00181 00182 for (id<MKAnnotation> annotation in annotationsToFilter) { 00183 // if annotation is not inside the coordinates, kick it 00184 if (isLocationNearToOtherLocation(annotation.coordinate, self.centerCoordinate, radius)) { 00185 [filteredAnnotations addObject:annotation]; 00186 } 00187 } 00188 00189 return [filteredAnnotations autorelease]; 00190 } 00191 00192 @end