Scott
Scott

Reputation: 1094

How to compute MKMapCamera centerCoordinateDistance programmatically in SwiftUI

I have a SwiftUI MapKitView that follows the pattern in https://www.hackingwithswift.com/books/ios-swiftui/advanced-mkmapview-with-swiftui adapted for macOS. In makeNSView I set the region for the interesting bit of the location I want to display, irrelevant of windows size and I can get this code to zoom appropriately by default whether the NSWindow is more landscape than portrait or vice versa.

 func makeNSView(context: Context) -> MKMapView {
    let mapView = MKMapView()
    mapView.delegate = context.coordinator
    mapView.mapType = .satellite
    mapView.pointOfInterestFilter = .excludingAll
    let region = MKCoordinateRegion(center: centroid, latitudinalMeters: 1160, longitudinalMeters: 1260)
    let fittedRegion = mapView.regionThatFits(region)
    mapView.setRegion(fittedRegion, animated: false)
}

It appears thatmapView.region is not actually updated upon the return of setRegion()

The rub is I want to orient the map other than true north, so I have to set a camera.

However, the fromDistance: parameter in creating MKMapCamera has to be computed from the region that was set, but what is the camera's field of view angle to determine how high it needs to be to include the correct extent for the window once the region is set? I basically want the zoom level set the same as via the fittedRegion and want to replicate that in the camera with the changed heading (with pitch at 0)

It appears the MKMapViewDelegate has a mapViewDidChangeVisibleRegion and I think the Coordinator is the delegate in SwiftUI. I can see the region on multiple calls to updateNSView, tho it takes a few calls before its actually set. I suspect setting the camera there will create another updateNSView() call which would pose problems.

How can I orient the map to include a given region extent regardless of window size with the zoom level and heading on initial load (but then lets the user manipulate as they see fit)..

Upvotes: 1

Views: 559

Answers (2)

Scott
Scott

Reputation: 1094

I think I figured it out.

Responding to func mapViewDidFinishLoadingMap(_ mapView: MKMapView) in the Coordinator and setting the mapView.camera.heading to an appropriate value there does what I'm intending.

Upvotes: 0

Asperi
Asperi

Reputation: 258285

Try the following

func makeNSView(context: Context) -> MKMapView {
    let mapView = MKMapView()
    mapView.delegate = context.coordinator
    mapView.mapType = .satellite
    mapView.pointOfInterestFilter = .excludingAll
    let region = MKCoordinateRegion(center: centroid, latitudinalMeters: 1160, longitudinalMeters: 1260)
    let fittedRegion = mapView.regionThatFits(region)

    DispatchQueue.main.async {
       mapView.setRegion(fittedRegion, animated: false)
    }
    return mapView
}

Upvotes: 0

Related Questions