Code Monkey home page Code Monkey logo

ios-cluster-marker's Introduction

iOS-cluster-marker

MAMapKit 点聚合

前述

核心类/接口

接口 说明 版本
AnnotationClusterViewController - (void)searchPoiWithKeyword:(NSString *)keyword; 根据关键字搜索poi点 n/a
CoordinateQuadTree - (void)buildTreeWithPOIs:(NSArray *)pois; 根据返回poi建树 n/a
AnnotationClusterViewController - (void)addAnnotationsToMapView:(MAMapView *)mapView; 把annotation添加到地图 n/a
AnnotationClusterViewController - (void)mapView:(MAMapView *)mapView regionDidChangeAnimated:(BOOL)animated; 响应地图区域变化回调,刷新annotations n/a

使用教程

  • 调用ClusterAnnotation文件夹下的代码能够实现poi点聚合,使用步骤如下:
  • 初始化coordinateQuadTree。

Objective-C

self.coordinateQuadTree = [[CoordinateQuadTree alloc] init];

Swift

var coordinateQuadTree = CoordinateQuadTree()
  • 获得poi数组pois后,创建coordinateQuadTree。
  • 项目Demo通过关键字搜索获得poi数组数据,具体见工程。此处从获得poi数组开始说明。
  • 创建四叉树coordinateQuadTree来建立poi的四叉树索引。
  • 创建过程较为费时,建议另开线程。创建四叉树完成后,计算当前mapView下需要显示的annotation。

Objective-C

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    /* 建立四叉树. */
    [self.coordinateQuadTree buildTreeWithPOIs:respons.pois];
        
    dispatch_async(dispatch_get_main_queue(), ^{
            /* 计算当前mapView区域内需要显示的annotation. */
            NSLog(@"First time calculate annotations.");
            [self addAnnotationsToMapView:self.mapView];
    });
});

Swift

DispatchQueue.global(qos: .default).async(execute: { [weak self] in
                
                self?.coordinateQuadTree.build(withPOIs: response.pois)
                self?.shouldRegionChangeReCalculate = true
                self?.addAnnotations(toMapView: (self?.mapView)!)
            })
  • 根据CoordinateQuadTree四叉树索引,计算当前zoomLevel下,mapView区域内的annotation。

Objective-C

- (void)addAnnotationsToMapView:(MAMapView *)mapView
{
    /* 判断是否已建树. */
    if (self.coordinateQuadTree.root == nil)
    {
        return;
    }
    /* 根据当前zoomLevel和zoomScale 进行annotation聚合. */
    double zoomScale = self.mapView.bounds.size.width / self.mapView.visibleMapRect.size.width;
    /* 基于先前建立的四叉树索引,计算当前需要显示的annotations. */
    NSArray *annotations = [self.coordinateQuadTree clusteredAnnotationsWithinMapRect:mapView.visibleMapRect
                                withZoomScale:zoomScale
                                 andZoomLevel:mapView.zoomLevel];
   
    /* 更新annotations. */
    [self updateMapViewAnnotationsWithAnnotations:annotations];
}

Swift

func addAnnotations(toMapView mapView: MAMapView) {
        synchronized(lock: self) { [weak self] in
            
            guard (self?.coordinateQuadTree.root != nil) || self?.shouldRegionChangeReCalculate != false else {
                NSLog("tree is not ready.")
                return
            }
            
            guard let aMapView = self?.mapView else {
                return
            }
            
            let visibleRect = aMapView.visibleMapRect
            let zoomScale = Double(aMapView.bounds.size.width) / visibleRect.size.width
            let zoomLevel = Double(aMapView.zoomLevel)
            
            DispatchQueue.global(qos: .default).async(execute: { [weak self] in
                
                let annotations = self?.coordinateQuadTree.clusteredAnnotations(within: visibleRect, withZoomScale: zoomScale, andZoomLevel: zoomLevel)
                
                self?.updateMapViewAnnotations(annotations: annotations as! Array<ClusterAnnotation>)
            })
        }
    }
  • 更新annotations。对比mapView里已有的annotations,吐故纳新。

Objective-C

/* 更新annotation. */
- (void)updateMapViewAnnotationsWithAnnotations:(NSArray *)annotations
{
    /* 用户滑动时,保留仍然可用的标注,去除屏幕外标注,添加新增区域的标注 */
    NSMutableSet *before = [NSMutableSet setWithArray:self.mapView.annotations];
    [before removeObject:[self.mapView userLocation]];
    NSSet *after = [NSSet setWithArray:annotations];
    
    /* 保留仍然位于屏幕内的annotation. */
    NSMutableSet *toKeep = [NSMutableSet setWithSet:before];
    [toKeep intersectSet:after];
    
    /* 需要添加的annotation. */
    NSMutableSet *toAdd = [NSMutableSet setWithSet:after];
    [toAdd minusSet:toKeep];
    
    /* 删除位于屏幕外的annotation. */
    NSMutableSet *toRemove = [NSMutableSet setWithSet:before];
    [toRemove minusSet:after];
    
    /* 更新. */
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.mapView addAnnotations:[toAdd allObjects]];
        [self.mapView removeAnnotations:[toRemove allObjects]];
    });
}

Swift

func updateMapViewAnnotations(annotations: Array<ClusterAnnotation>) {
        
        /* 用户滑动时,保留仍然可用的标注,去除屏幕外标注,添加新增区域的标注 */
        let before = NSMutableSet(array: mapView.annotations)
        before.remove(mapView.userLocation)
        let after: Set<NSObject> = NSSet(array: annotations) as Set<NSObject>
        
        /* 保留仍然位于屏幕内的annotation. */
        var toKeep: Set<NSObject> = NSMutableSet(set: before) as Set<NSObject>
        toKeep = toKeep.intersection(after)
        
        /* 需要添加的annotation. */
        let toAdd = NSMutableSet(set: after)
        toAdd.minus(toKeep)
        
        /* 删除位于屏幕外的annotation. */
        let toRemove = NSMutableSet(set: before)
        toRemove.minus(after)
        
        DispatchQueue.main.async(execute: { [weak self] () -> Void in
            self?.mapView.addAnnotations(toAdd.allObjects)
            self?.mapView.removeAnnotations(toRemove.allObjects)
        })
    }

架构

Controllers
  • <UIViewController>
    • AnnotationClusterViewController poi点聚合
    • PoiDetailViewController 显示poi详细信息列表
View
  • MAAnnotationView
    • ClusterAnnotationView 自定义的聚合annotationView
Models
  • Conform to <MAAnnotation>
    • ClusterAnnotation 记录annotation的信息,如其代表的poi数组、poi的个数、poi平均坐标,并提供两个annotation是否Equal的判断
  • CoordinateQuadTree 封装的四叉树类
  • QuadTree 四叉树基本算法

截图效果

ClusterAnnotation2 ClusterAnnotation1

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.