2

I am having a hard time finding examples for mapbox sdk iOS v10 annotation clustering. Everything seems to be outdated. Using print statement it seems that the annotations are now clustering, but nothing displays on the map anymore. I am having trouble, this is my code.

class MapViewController: UIViewController {
    
   internal var mapView: MapView!
   var initialCamera: CameraOptions?
   var locationToAnnotation: [CLLocation: CustomAnnotationWrapper] = [:]
   var blockedFeed: [String] = []
   var blockedFeeder: [String] = []
   var mapUser: String = ""
    
   override public func viewDidLoad() {
       
       super.viewDidLoad()
       
       
       let myResourceOptions = ResourceOptions(accessToken: "xxxxxxxxxxx")
       let cameraOptions = CameraOptions(center: CLLocationCoordinate2D(latitude: 39.8, longitude: -86.2), zoom: 9, bearing: 0, pitch: 0)
       let styleURI = StyleURI(rawValue: "mapbox://styles/xxxxxxxxx")
       let myMapInitOptions = MapInitOptions(resourceOptions: myResourceOptions, cameraOptions: cameraOptions, styleURI: styleURI)
       mapView = MapView(frame: view.bounds, mapInitOptions: myMapInitOptions)
       mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
       mapView.location.options.puckType = .puck2D()
       mapView.annotations.makePointAnnotationManager().delegate = self
       mapView.gestures.options.rotateEnabled = false
       mapView.gestures.options.pitchEnabled = false
       
       self.view.addSubview(mapView)
       
       if let initialCamera = initialCamera {
           mapView.camera.fly(to: initialCamera, duration: 1)
       }
       
       fetchPublic()
   }
    
    
    func fetchPublic(){
        let pointManager = self.mapView.annotations.makePointAnnotationManager()
        var clusters: [AnnotationCluster] = []
        var clusterAnnotations: [AnnotationCluster] = []
        
        let publicDB = CKContainer.default().publicCloudDatabase
        let date = NSDate(timeInterval: 12 * 3600, since: NSDate() as Date)
        let date1 = NSDate()
        let predicate = NSPredicate(format: "start < %@ && end > %@", date, date1)
        let query = CKQuery(recordType: "event", predicate:predicate)
        publicDB.fetch(withQuery: query, inZoneWith: nil)
        { result in
            switch result {
            case .success((let matchResults, _)):
                for matchResult in matchResults {
                    switch matchResult.1 {
                    case .success(let record):
                        if let location = record["location1"] as? CLLocation
                           {
                            let identified = record.recordID
                            
                                    var point = PointAnnotation(point: Point(LocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)))
                                        
                                            point.image = .init(image: UIImage(named: "Image 2")!, name: "Image 2")
                                       
                                    point.iconAnchor = .bottom
                                    if let recordName = record["name"] as? String{
                                        point.textField = recordName
                                        point.textAnchor = .top
                                        point.textSize = 10
                                    }
                                    let customAnnotation = CustomAnnotationWrapper(annotation: point, recordID: identified, identifier: UUID().uuidString)
                                    
                                    var addedToCluster = false
                                    for (index, cluster) in clusters.enumerated() {
                                                let clusterLocation = CLLocation(latitude: cluster.center.latitude, longitude: cluster.center.longitude)
                                                let annotationLocation = CLLocation(latitude: point.point.coordinates.latitude, longitude: point.point.coordinates.longitude)
                                                let clusteringDistanceThreshold = 50.0
                                                let distance = clusterLocation.distance(from: annotationLocation)
                                                if distance < clusteringDistanceThreshold {
                                                    clusters[index].annotations.append(customAnnotation)
                                                    addedToCluster = true
                                                    break
                                                }
                                            }
                                            if !addedToCluster {
                                                clusters.append(AnnotationCluster(center: point.point.coordinates, annotations: [customAnnotation]))
                                                print("clustering\(clusters)")
                                            }
                                    //
                                    DispatchQueue.main.async {
                                            for annotation in pointManager.annotations {
                                                var addedToCluster = false
                                                for (index, cluster) in clusterAnnotations.enumerated() {
                                                    let clusterLocation = CLLocation(latitude: cluster.center.latitude, longitude: cluster.center.longitude)
                                                    let annotationLocation = CLLocation(latitude: annotation.point.coordinates.latitude, longitude: annotation.point.coordinates.longitude)
                                                    let clusteringDistanceThreshold = 50.0
                                                    let distance = clusterLocation.distance(from: annotationLocation)

                                                    if distance < clusteringDistanceThreshold {
                                                        let customAnnotationWrapper = CustomAnnotationWrapper(annotation: annotation, recordID: nil, identifier: UUID().uuidString)
                                                        clusterAnnotations[index].annotations.append(customAnnotationWrapper)
                                                        addedToCluster = true
                                                        break
                                                    }
                                                }

                                                if !addedToCluster {
                                                    let customAnnotationWrapper = CustomAnnotationWrapper(annotation: annotation, recordID: nil, identifier: UUID().uuidString)
                                                    clusterAnnotations.append(AnnotationCluster(center: annotation.point.coordinates, annotations: [customAnnotationWrapper]))
                                                }
                                            }

                                            for cluster in clusterAnnotations {
                                                if cluster.annotations.count > 1 {
                                                    var clusterAnnotation = PointAnnotation(point: Point(LocationCoordinate2D(latitude: cluster.center.latitude, longitude: cluster.center.longitude)))
                                                    clusterAnnotation.image = .init(image: UIImage(named: "red_pin")!, name: "red_pin")
                                                    clusterAnnotation.iconAnchor = .bottom
                                                    pointManager.annotations.append(clusterAnnotation)
                                                }

                                                for (index, cluster) in clusters.enumerated() {
                                                    let clusterLocation = CLLocation(latitude: cluster.center.latitude, longitude: cluster.center.longitude)
                                                    let annotationLocation = CLLocation(latitude: point.point.coordinates.latitude, longitude: point.point.coordinates.longitude)
                                                    let clusteringDistanceThreshold = 50.0
                                                    let distance = clusterLocation.distance(from: annotationLocation)

                                                    if distance < clusteringDistanceThreshold {
                                                        clusters[index].annotations.append(customAnnotation)
                                                        addedToCluster = true
                                                        break
                                                    }
                                                }

                                                if !addedToCluster {
                                                    let newCluster = AnnotationCluster(center: point.point.coordinates, annotations: [customAnnotation])
                                                    clusters.append(newCluster)
                                                }
                                            }

                                            pointManager.delegate = self
                                        }
                                    //
                                    /*
                                            DispatchQueue.main.async {
                                                pointManager.annotations.append(point)
                                                pointManager.delegate = self
                                                self.locationToAnnotation[CLLocation(latitude: point.point.coordinates.latitude, longitude: point.point.coordinates.longitude)] = customAnnotation
                                            }
                                     */
                                }
                            }
                        }
                    case .failure(let error): print(error)
                    }
                }
            case .failure(let error): print(error)
            }
        }
    }
    
    func fetchPrivateMap(){
        let pointManager = self.mapView.annotations.makePointAnnotationManager()
        let publicDB = CKContainer.default().publicCloudDatabase
        let date = NSDate()
        let predicate = NSPredicate(format: "endtime > %@", date)
        let query = CKQuery(recordType: "private", predicate:  predicate)
        publicDB.fetch(withQuery: query, inZoneWith: nil)
        { result in
            switch result {
            case .success((let matchResults, _)):
                for matchResult in matchResults {
                    switch matchResult.1 {
                    case .success(let record):
                        if let listed = record["invites"] as? [String],
                           let location = record["location2"] as? CLLocation,
                           let phost = record["host"] as? String
                           {
                            let identified = record.recordID
                                for attendant in listed{
                                    if self.mapUser == attendant || self.mapUser == phost{
                                        var point = PointAnnotation(point: Point(LocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)))
                                            point.image = .init(image: UIImage(named: "red_pin")!, name: "red_pin")
                                            point.iconAnchor = .bottom
                                        if let recordName = record["title"] as? String{
                                            point.textField = recordName
                                            point.textAnchor = .top
                                            point.textSize = 10
                                        }
                                        let customAnnotation = CustomAnnotationWrapper(annotation: point, recordID: identified, identifier: UUID().uuidString)
                                            DispatchQueue.main.async {
                                                pointManager.annotations.append(point)
                                                pointManager.delegate = self
                                                self.locationToAnnotation[CLLocation(latitude: point.point.coordinates.latitude, longitude: point.point.coordinates.longitude)] = customAnnotation
                                        }
                                    }
                                }
                            }
                    case .failure(let error): print(error)
                    }
                }
            case .failure(let error): print(error)
            }
        }
    }
    
}
//
struct ClusterCenter: Hashable {
    let latitude: Double
    let longitude: Double

    init(_ coordinate: CLLocationCoordinate2D) {
        self.latitude = coordinate.latitude
        self.longitude = coordinate.longitude
    }
}
//
struct AnnotationCluster {
    let center: CLLocationCoordinate2D
    var annotations: [CustomAnnotationWrapper]
}

class CustomAnnotationWrapper {
    var annotation: PointAnnotation
    let recordID: CKRecord.ID?
    let identifier: String
        
        init(annotation: PointAnnotation, recordID: CKRecord.ID?, identifier: String) {
            self.annotation = annotation
            self.recordID = recordID
            self.identifier = identifier
        }
}

extension MapViewController: AnnotationInteractionDelegate {
    func annotationManager(_ manager: MapboxMaps.AnnotationManager, didDetectTappedAnnotations annotations: [MapboxMaps.Annotation]) {
        if let pointAnnotation = annotations.first as? PointAnnotation {
                let tappedLocation = CLLocation(latitude: pointAnnotation.point.coordinates.latitude, longitude: pointAnnotation.point.coordinates.longitude)
                if let closestAnnotation = locationToAnnotation.min(by: { (a, b) -> Bool in
                    return a.key.distance(from: tappedLocation) < b.key.distance(from: tappedLocation)
                }) {
                    let customAnnotation = closestAnnotation.value
                    let recordID = customAnnotation.recordID
                    let sheetView = EventView(eventLoc: pointAnnotation.point.coordinates, identify: recordID!)
                    let hostingController = UIHostingController(rootView: sheetView)
                    hostingController.modalPresentationStyle = .popover
                    present(hostingController, animated: true, completion: nil)
                } else {
                    print("Custom annotation not found")
                }
            }
    }
    
    private func presentSheet<Content: View>(with content: Content) {
        let sheet = UIHostingController(rootView: content)
        sheet.modalPresentationStyle = .popover
        present(sheet, animated: true, completion: nil)
    }
}

struct MapBoxMapView: UIViewControllerRepresentable {
    
    @Binding var reloadMap: Bool
    @ObservedObject var locationManager: LocationManager
    
    func makeUIViewController(context: Context) -> MapViewController {
        locationManager.requestLoc()
        let viewController = MapViewController()
        viewController.initialCamera = CameraOptions(center: locationManager.eventLocation.coordinate, zoom: 9)
        return viewController
        //return MapViewController()
    }
    
    func updateUIViewController(_ uiViewController: MapViewController, context: Context) {
        if reloadMap {
            uiViewController.initialCamera = CameraOptions(center: locationManager.eventLocation.coordinate, zoom: 9)
            uiViewController.viewDidLoad()
            DispatchQueue.main.async {
                self.reloadMap = false
            }
        }
    }
}
Steve
  • 1,121
  • 1
  • 12
  • 32
  • But... you are using both the `clusters` and `clusterAnnotations` variables, but you are not merging them in any meaningful way. The `clusters` variable stores a list of `AnnotationCluster` objects, and the `clusterAnnotations` variable stores a list of `CustomAnnotationWrapper` objects. – VonC Aug 13 '23 at 20:08

0 Answers0