第一篇文章:百度地图聚合功能

近期公司需求在地图上展示点部坐标信息,结果后台一次性返回了1200多个点部,加载到地图上连6S都巨卡,所以自己去弄了一个百度API上的一个聚合功能,文档写的相关内容很少,Demo也没有对数据量过多的时候的优化,所以就自己研究了一下,希望能和大家学习一下,编程道路上还是个新人,望多指教。


第一篇文章:百度地图聚合功能_第1张图片
WechatIMG101.jpeg

大概的实现效果界面就是这样

相关的百度静态库(BMKClusterManager)导入就不做说明了,API里面有很详细的说明。

首先创一个百度大头针BMKPointAnnotation的子类,在里面对大头针的样式(这里用的Label)和自定义多少个大头针聚合为一体(size)和它的显示样式颜色等


/* *点聚合Annotation */

@interface ClusterAnnotation : BMKPointAnnotation

///所包含annotation个数

@property (nonatomic, assign) NSInteger size;

@property (nonatomic ,strong) NSString * AnnotationAddress;

@end

@implementation ClusterAnnotation

@synthesize size = _size;

@end

/* *点聚合AnnotationView */

@interface ClusterAnnotationView : BMKPinAnnotationView {

}

@property (nonatomic, assign) NSInteger size;

@property (nonatomic, strong) UILabel *label;

@end

@implementation ClusterAnnotationView

@synthesize size = _size;

@synthesize label = _label;- (id)initWithAnnotation:(id)annotation reuseIdentifier:(NSString *)reuseIdentifier {

self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];

if (self) {

[self setBounds:CGRectMake(0.f, 0.f, 22.f, 22.f)];

_label = [[UILabel alloc] initWithFrame:CGRectMake(0.f, 0.f, 40.f, 40.f)];

_label.layer.masksToBounds = YES;

_label.layer.cornerRadius =20;

_label.layer.borderWidth = 3;

_label.layer.borderColor = [UIColor whiteColor].CGColor;

_label.textColor = [UIColor whiteColor];

_label.font = [UIFont systemFontOfSize:15];

_label.textAlignment = NSTextAlignmentCenter;

[self addSubview:_label];

self.alpha = 0.85;

}

return self;

}

- (void)setSize:(NSInteger)size {

_size = size;

if (_size == 1) {

self.label.hidden = YES;

self.pinColor = BMKPinAnnotationColorPurple;

return;

}

self.label.hidden = NO;

if (size > 200) {

self.label.backgroundColor =[UIColor colorWithHexString:@"#5b78c9"];

} else if (size > 100) {

self.label.backgroundColor = [UIColor colorWithHexString:@"#9388ff"];

} else if (size > 50){

self.label.backgroundColor = [UIColor colorWithHexString:@"#62a5d3"];

} else if (size > 20){

self.label.backgroundColor = [UIColor colorWithHexString:@"#5688e9"];

} else {

self.label.backgroundColor = [UIColor colorWithHexString:@"#889cff"];

}

_label.text = [NSString stringWithFormat:@"%ld", size];

}

@end

之后需要在使用的控制器中导入几个全局管理类


@interface ClusterDemoViewController() {

BMKClusterManager *_clusterManager;//点聚合管理类

NSInteger _clusterZoom;//聚合级别

NSMutableArray *_clusterCaches;//点聚合缓存标注

}

接下来对没个管理类进行设置,这里的_clusterCaches是将百度地图的每个等级的比例(比例尺等级为3-22)所需要展现的大头针个数进行了一个缓存处理。_clusterManager存储所有的标注,它会将所有标注进行处理,比如说在什么时候需要聚合什么时候需要分离。需要注意的是导入的坐标点是否为百度经纬度,如果为GPS或者其他的需要转换。


//#pragma mark - 设置百度地图大头针和代理方法

-(void)didSetAnnotations{

//适配ios7

if( ([[[UIDevice currentDevice] systemVersion] doubleValue]>=7.0)) {

self.navigationController.navigationBar.translucent = NO;

}

_clusterCaches = [[NSMutableArray alloc] init];

for (NSInteger i = 3; i < 22; i++) {

[_clusterCaches addObject:[NSMutableArray array]];

}

_clusterManager = [[BMKClusterManager alloc] init];

for (NSDictionary * tempDic in self.pointArr) {

CLLocationCoordinate2D coor = CLLocationCoordinate2DMake([tempDic[@"Latitude"] doubleValue],  [tempDic[@"Longitude"] doubleValue]);

NSDictionary *locDic = BMKConvertBaiduCoorFrom(coor,BMK_COORDTYPE_GPS);

CLLocationCoordinate2D newCoor =BMKCoorDictionaryDecode(locDic);

if (!(coor.longitude ==0 && coor.longitude == 0)) {

ClusterAnnotation* annotation = [[ClusterAnnotation alloc]init];

annotation.coordinate = newCoor;

annotation.title = tempDic[@"Company"];

annotation.AnnotationAddress = tempDic[@"Address"];

[self.annotationArr addObject:annotation];

//添加大头针到管理类

BMKClusterItem *clusterItem = [[BMKClusterItem alloc] init];

clusterItem.coor = newCoor;

[_clusterManager addClusterItem:clusterItem];

}

}

}

接下来是实现聚合最麻烦的地方,Demo里面给的案例因为只有20个点,所以完全不需要做优化,我照着写就很卡,我的处理是点部在当前屏幕上加载


#pragma mark - 更新聚合状态

//更新聚合状态

- (void)updateClusters {

//当前屏幕中心经纬度

CLLocationDegrees centerLatitude= _baiduMapView.centerCoordinate.latitude;

CLLocationDegrees centerLongitude = _baiduMapView.centerCoordinate.longitude;

//当前地图经纬度跨度范围

__block CLLocationDegrees smallLatitude =centerLatitude - (_baiduMapView.region.span.latitudeDelta/2.f);

__block CLLocationDegrees bigLatitude =  centerLatitude + (_baiduMapView.region.span.latitudeDelta/2.f);

__block CLLocationDegrees smallLongitude =centerLongitude - (_baiduMapView.region.span.longitudeDelta/2.f);

__block CLLocationDegrees bigLongitude =  centerLongitude + (_baiduMapView.region.span.longitudeDelta/2.f);

_clusterZoom = (NSInteger)_baiduMapView.zoomLevel;

@synchronized(_clusterCaches) {

__block NSMutableArray *clusters = [_clusterCaches objectAtIndex:(_clusterZoom-3)];

if (clusters.count > 0) {

[_baiduMapView removeAnnotations:_baiduMapView.annotations];

NSMutableArray *tmp  = [[NSMutableArray alloc] init];

//获取聚合后的标注

__block NSArray *array = [_clusterManager getClusters:_clusterZoom];

for (BMKCluster *item in array) {

//创建大头针

ClusterAnnotation *annotation = [[ClusterAnnotation alloc] init];

annotation.coordinate = item.coordinate;

//创建大头

if (  (smallLatitude <= annotation.coordinate.latitude)

&& (bigLatitude  >= annotation.coordinate.latitude)

&& (smallLongitude<= annotation.coordinate.longitude)

&& (bigLongitude  >= annotation.coordinate.longitude)) {

annotation.size = item.size;

for (ClusterAnnotation * tempAnn in self.annotationArr) {

//                        CLLocationCoordinate2D coor = CLLocationCoordinate2DMake([tempDic[@"Latitude"] doubleValue],  [tempDic[@"Longitude"] doubleValue]);

//判断是否为大头针

if (annotation.coordinate.latitude == tempAnn.coordinate.latitude

&& annotation.coordinate.longitude == tempAnn.coordinate.longitude && annotation.size == 1) {

annotation.title =tempAnn.title;

annotation.AnnotationAddress = tempAnn.AnnotationAddress;

break;

}else{

annotation.title = [NSString stringWithFormat:@"共%ld个点部", item.size];

}

}

[tmp addObject:annotation];

}

}

//满足在指定范围内则添加

[_baiduMapView addAnnotations:tmp];

} else {

// WS(weakSelf);

dispatch_async(dispatch_get_global_queue(0, 0), ^{

///获取聚合后的标注

__block NSArray *array = [_clusterManager getClusters:_clusterZoom];

dispatch_async(dispatch_get_main_queue(), ^{

NSMutableArray *tmp = [[NSMutableArray alloc] init];

for (BMKCluster *item in array) {

//创建大头针

ClusterAnnotation *annotation = [[ClusterAnnotation alloc] init];

annotation.coordinate = item.coordinate;

[clusters addObject:annotation];

//满足在指定范围内则添加

if (  (smallLatitude <= annotation.coordinate.latitude)

&& (bigLatitude  >= annotation.coordinate.latitude)

&& (smallLongitude<= annotation.coordinate.longitude)

&& (bigLongitude  >= annotation.coordinate.longitude)) {

annotation.size = item.size;

//遍历给大头针标题赋值

for (ClusterAnnotation * tempAnn in self.annotationArr){

// CLLocationCoordinate2D coor = CLLocationCoordinate2DMake([tempDic[@"Latitude"] doubleValue],  [tempDic[@"Longitude"] doubleValue]);

//判断是否为大头针

if (annotation.coordinate.latitude == tempAnn.coordinate.latitude

&& annotation.coordinate.longitude == tempAnn.coordinate.longitude && annotation.size == 1) {

annotation.title =tempAnn.title;

annotation.AnnotationAddress = tempAnn.AnnotationAddress;

break;

}else{

annotation.title = [NSString stringWithFormat:@"共%ld个点部", item.size];

}

}

[tmp addObject:annotation];

}

}

[_baiduMapView removeAnnotations:_baiduMapView.annotations];

[_baiduMapView addAnnotations:tmp];

});

});

}

}

}

上面的能理解写完以后基本就完成了,之后就是在合适的地方调用那个方法就可以了,这里的代码我放上来时没有封装,写的也比较粗糙,相关注释也写在上面了,聚合最复杂的地方也是这部分


#pragma mark - BMKMapViewDelegate

// 根据anntation生成对应的View

- (BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id)annotation

{

//普通annotation

NSString *AnnotationViewID = @"ClusterMark";

ClusterAnnotation *cluster = (ClusterAnnotation*)annotation;

ClusterAnnotationView *annotationView = [[ClusterAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationViewID];

annotationView.size = cluster.size;

annotationView.draggable = YES;

annotationView.annotation = cluster;

return annotationView;

}

/**

*当点击annotation view弹出的泡泡时,调用此接口

*@param mapView 地图View

*@param view 泡泡所属的annotation view

*/

- (void)mapView:(BMKMapView *)mapView annotationViewForBubble:(BMKAnnotationView *)view {

if ([view isKindOfClass:[ClusterAnnotationView class]]) {

ClusterAnnotation *clusterAnnotation = (ClusterAnnotation*)view.annotation;

if (clusterAnnotation.size > 1) {

[mapView setCenterCoordinate:view.annotation.coordinate];

[mapView zoomIn];

}

}

}

/**

*地图初始化完毕时会调用此接口

*@param mapview 地图View

*/

- (void)mapViewDidFinishLoading:(BMKMapView *)mapView {

[self updateClusters];

}

/**

*地图渲染每一帧画面过程中,以及每次需要重绘地图时(例如添加覆盖物)都会调用此接口

*@param mapview 地图View

*@param status 此时地图的状态

*/

- (void)mapView:(BMKMapView *)mapView onDrawMapFrame:(BMKMapStatus *)status {

if (_clusterZoom != 0 && _clusterZoom != (NSInteger)mapView.zoomLevel) {

[self updateClusters];

}

}

你可能感兴趣的:(第一篇文章:百度地图聚合功能)