iOS 高德地图点聚合功能
最近公司有个地图上加很多点的需求,因为web端使用了点聚合功能,业主也让我们做一个功能
这里使用了
pod 'AMap3DMap-NO-IDFA'
pod 'AMapLocation-NO-IDFA'
pod 'AMapSearch-NO-IDFA'
我们地图上的点是服务器得到的,所以其实只需要 AMap3DMap就可以了
//MARK:设置点
func setPoint(_ arr:[GYHomeTableModel]) {
mapView.removeAnnotations(mapView.annotations)
self.poiAnnotations.removeAll()
var rect: MAMapRect = MAMapRectZero
for (i,model) in arr.enumerated() {
let poi = GYMapPOI()
let latitude = (Double)(model.lat)
let longitude = (Double)(model.lng)
poi.location = AMapGeoPoint.location(withLatitude:CGFloat(latitude), longitude: CGFloat(longitude))
poi.model = model
poi.annotationTag = i + 1
poi.pro_type = model.organ_id
// poi.type = model.
if model.project_name.count > 6 {
let str:String = String(model.project_name.prefix(6))
poi.name = "\(str)..."
}else {
poi.name = model.project_name
}
self.poiAnnotations.append(poi)
let annotationMapPoint = MAMapPointForCoordinate(CLLocationCoordinate2DMake(CLLocationDegrees(poi.location!.latitude), CLLocationDegrees(poi.location!.longitude)))
///annotation相对于中心点的对角线坐标
let diagonalPoint = CLLocationCoordinate2DMake(mapView.centerCoordinate.latitude - (CLLocationDegrees(poi.location!.latitude) - mapView.centerCoordinate.latitude),mapView.centerCoordinate.longitude - (CLLocationDegrees(poi.location!.longitude) - mapView.centerCoordinate.longitude))
let diagonalPointMapPoint = MAMapPointForCoordinate(diagonalPoint)
let annotationRect = MAMapRectMake(min(annotationMapPoint.x, diagonalPointMapPoint.x), min(annotationMapPoint.y, diagonalPointMapPoint.y), abs(annotationMapPoint.x - diagonalPointMapPoint.x), abs(annotationMapPoint.y - diagonalPointMapPoint.y));
rect = MAMapRectUnion(rect, annotationRect)
}
mapView.setVisibleMapRect(rect, edgePadding: UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5), animated: true)
synchronized(lock: self) { [weak self] in
self?.shouldRegionChangeReCalculate = false
self?.mapView.removeAnnotations(self?.mapView.annotations)
DispatchQueue.global(qos: .default).async(execute: { [weak self] in
self?.coordinateQuadTree.build(withPOIs: self?.poiAnnotations)
self?.shouldRegionChangeReCalculate = true
// DispatchQueue.main.async(execute: {
// self?.addAnnotations(toMapView: (self?.mapView)!)
// })
})
}
}
这里是服务器拿到数据 并把服务器数据格式转化成AMapPOI格式 我这里是写了一个继承AMapPOI的model。用它来接受来自服务器的数据,
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<<span style="color: #d0a8ff">ClusterAnnotation>)
})
}
}
func synchronized(lock: AnyObject, closure: () -> ()) {
objc_sync_enter(lock)
closure()
objc_sync_exit(lock)
}
//MARK: - MAMapViewDelegate
func mapView(_ mapView: MAMapView!, didSelect view: MAAnnotationView!) {
mapView.deselectAnnotation(view.annotation, animated: true)
if let annotation = view.annotation as? ClusterAnnotation {
if annotation.pois.count > 1 {
var rect: MAMapRect = MAMapRectZero
for item in annotation.pois {
if let poi = item as? GYMapPOI {
let annotationMapPoint = MAMapPointForCoordinate(CLLocationCoordinate2DMake(CLLocationDegrees(poi.location!.latitude), CLLocationDegrees(poi.location!.longitude)))
///annotation相对于中心点的对角线坐标
let diagonalPoint = CLLocationCoordinate2DMake(annotation.coordinate.latitude - (CLLocationDegrees(poi.location.latitude) - annotation.coordinate.latitude),annotation.coordinate.longitude - (CLLocationDegrees(poi.location.longitude) - annotation.coordinate.longitude))
let diagonalPointMapPoint = MAMapPointForCoordinate(diagonalPoint)
let annotationRect = MAMapRectMake(min(annotationMapPoint.x, diagonalPointMapPoint.x), min(annotationMapPoint.y, diagonalPointMapPoint.y), abs(annotationMapPoint.x - diagonalPointMapPoint.x), abs(annotationMapPoint.y - diagonalPointMapPoint.y));
rect = MAMapRectUnion(rect, annotationRect)
}
}
if !MAMapRectIsEmpty(rect) {
mapView.setVisibleMapRect(rect, edgePadding: UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5), animated: true)
}
}
} else if let ann = view.annotation as? GYCustomPointAnnotation {
guard let annView = view as? GYCustomAnnotationView else{return}
if lastAnnotation != nil {
lastAnnotation?.isSelected = false
for item in unitAnnotations {
if item.annotationTag == lastAnnotation!.annotationTag {
item.isSelected = lastAnnotation!.isSelected
let info = getNameAndStr(item)
let annView = mapView.view(for: item) as! GYCustomAnnotationView
annView.image = UIImage.map(info.0, text: info.1, isSelected: item.isSelected)
break
}
}
}
let annInfo = getNameAndStr(ann)
ann.isSelected = true
annView.image = UIImage.map(annInfo.0, text: annInfo.1, isSelected: ann.isSelected)
// lastAnnoView = annView
lastAnnotation = ann
if ann.isSelected {//是否选中
infoView?.tableAndDetailView?.showDetail()
infoView?.tableAndDetailView?.DetailData(ann.model)
infoView?.tableAndDetailView?.titleLabel.text = ann.model.project_name;
popView?.toCenter();
}else {
infoView?.tableAndDetailView?.showTable()
}
}
}
func mapView(_ mapView: MAMapView!, viewFor annotation: MAAnnotation!) -> MAAnnotationView! {
if annotation is ClusterAnnotation {
let annotation = annotation as! ClusterAnnotation
let pointReuseIndetifier = "pointReuseIndetifier"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: pointReuseIndetifier) as? ClusterAnnotationView
if annotationView == nil {
annotationView = ClusterAnnotationView(annotation: annotation, reuseIdentifier: pointReuseIndetifier)
}
annotationView?.annotation = annotation
annotationView?.count = UInt((annotation ).count)
switch type {
case 1:
annotationView?.backColor = UIColor.init(named: "DarkOrangeColor")
case 2:
annotationView?.backColor = UIColor.init(named: "OrangeColor")
case 3:
annotationView?.backColor = UIColor.init(named: "RedColor")
case 4:
annotationView?.backColor = UIColor.init(named: "MainColor")
case 5:
annotationView?.backColor = UIColor.init(named: "GreenColor")
default:
break
}
return annotationView
}
if annotation is GYCustomPointAnnotation {
let anno = annotation as! GYCustomPointAnnotation
var annView = mapView.dequeueReusableAnnotationView(withIdentifier: "annotationResuseIndetifier")
// var annView = mapView.dequeueReusableAnnotationView(withIdentifier: "annotationResuseIndetifier")as? GYCustomAnnotationView
if annView == nil {
annView = GYCustomAnnotationView(annotation: anno, reuseIdentifier: "annotationResuseIndetifier")
}
annView?.tag = anno.annotationTag
annView?.canShowCallout = false
annView?.isDraggable = false
var imageStr = ""
if anno.type == 1 {//广州冠粤
imageStr = ""
}else if (anno.type == 2){//路基桥涵(工程一部)
imageStr = "pop_map_yellow"
}else if (anno.type == 3){//路面工程(工程二部)
imageStr = "pop_map_red"
}else if (anno.type == 4) {//地方项目(工程三部)
imageStr = "pop_map_blue"
}else if (anno.type == 5) {//养护项目
imageStr = "pop_map_green"
}
annView?.image = UIImage.map(imageStr, text: anno.contentStr as NSString, isSelected: anno.isSelected)
//设置偏移量,使其旗子正好插在位置
annView?.centerOffset = CGPoint(x: annView!.image.size.width/2, y: -annView!.image.size.height/2)
return annView
}
return nil
}
func mapView(_ mapView: MAMapView!, didDeselect view: MAAnnotationView!) {
// customCalloutView.dismiss()
// customCalloutView.delegate = nil
}
func mapView(_ mapView: MAMapView!, regionDidChangeAnimated animated: Bool) {
print("zoomLevel",mapView.zoomLevel)
let visibleRect = mapView.visibleMapRect
let zoomScale = Double(mapView.bounds.size.width) / visibleRect.size.width
let zoomLevel = Double(mapView.zoomLevel)
if let annotations = self.coordinateQuadTree.clusteredAnnotations(within: visibleRect, withZoomScale: zoomScale, andZoomLevel: zoomLevel) as? [ClusterAnnotation] {
mapView.removeAnnotations(unitAnnotations)
unitAnnotations.removeAll()
var newAnnotations = [ClusterAnnotation]()
for index in (0..
let annotation = annotations[index]
if annotation.pois.count > 1 {
// annotation.type =
newAnnotations.append(annotation)
} else {
for item in annotation.pois {
if let poi = item as? GYMapPOI {
let ann = GYCustomPointAnnotation()
ann.annotationTag = poi.annotationTag
ann.type = poi.pro_type
ann.coordinate = CLLocationCoordinate2DMake(CLLocationDegrees(poi.location!.latitude), CLLocationDegrees(poi.location!.longitude))
ann.contentStr = poi.name
ann.model = poi.model
if lastAnnotation != nil {
if lastAnnotation?.annotationTag == ann.annotationTag {
ann.isSelected = lastAnnotation!.isSelected
}else {
ann.isSelected = false
}
}
unitAnnotations.append(ann)
}
}
}
}
mapView.addAnnotations(unitAnnotations)
updateMapViewAnnotations(annotations: newAnnotations)
}
}
这里主要还是在移动屏幕以后,找到最后点击的view ,这边是把它先存起来,用的时候在数组里面遍历一次,通过tag寻找他 ,改变他的选中状态。 还有就是 点击聚合 展示这个聚合所有的点。需要在didSelect方法里面判断是点击的聚合还是view。聚合的话,获取聚合里面所有的点,把这些点坐标转换一下,展示在地图里面
还有一些关键的类,是直接用的官方demo的代码,我就懒得copy了,。贴一下他们的地址 https://lbs.amap.com/dev/demo/cluster-marker#iOS
https://github.com/amap-demo/iOS-cluster-marker
吐槽一下,他们的代码还需要自己pod install 一下,不然不能运行
非常感谢我们组长 最关键的大部分都是他帮助我写的,所以今天买了老干妈请他吃