2

I am trying to limit maximum zoom level in my swift application without which my app is crashing with memory overload during zooming. I am following the suggestions present in Is there way to limit MKMapView maximum zoom level? One of the suggestion is to implement regionDidChangeAnimated with following code in Objective-C. Following is the code

- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
    // Constrain zoom level to 8.
    if( [mapView zoomLevel] < 8 )
    {
        [mapView setCenterCoordinate:mapView.centerCoordinate 
            zoomLevel:8 
            animated:NO];
    }
}

I am trying to convert it into Swift and facing problems. How do I convert into swift

2 Answers2

1

I think you can use mapView.camera.altitude instead.

So it will be like:

func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
    if mapView.camera.altitude < 8 {
        mapView.camera.altitude = 8
    }
}

Also remember that you will have to add MKMapViewDelegate as a superclass (class ViewController : UIViewController, MKMapViewDelegate)

Good luck!

Best Regards Eskils.

Eskils
  • 126
  • 8
  • This is exactly how I did it. I should note that changing that value also changes the zoom, so you'll need a flag, to prevent excessive actions (I do a lot, in my region change callback). – Chris Marshall Jul 28 '23 at 19:47
1

I have a swift version of what you looking for, i can't remember where i got it from but i shouldn't be credited for it.

extension MKMapView {
var MERCATOR_OFFSET : Double {
    return 268435456.0
}

var MERCATOR_RADIUS : Double  {
    return 85445659.44705395
}

private func longitudeToPixelSpaceX(longitude: Double) -> Double {
    return round(MERCATOR_OFFSET + MERCATOR_RADIUS * longitude * Double.pi / 180.0)
}

private func latitudeToPixelSpaceY(latitude: Double) -> Double {
    return round(MERCATOR_OFFSET - MERCATOR_RADIUS * log((1 + sin(latitude * Double.pi / 180.0)) / (1 - sin(latitude * Double.pi / 180.0))) / 2.0)
}

private  func pixelSpaceXToLongitude(pixelX: Double) -> Double {
    return ((round(pixelX) - MERCATOR_OFFSET) / MERCATOR_RADIUS) * 180.0 / Double.pi;
}

private func pixelSpaceYToLatitude(pixelY: Double) -> Double {
    return (Double.pi / 2.0 - 2.0 * atan(exp((round(pixelY) - MERCATOR_OFFSET) / MERCATOR_RADIUS))) * 180.0 / Double.pi;
}

private func coordinateSpan(withMapView mapView: MKMapView, centerCoordinate: CLLocationCoordinate2D, zoomLevel: UInt) ->MKCoordinateSpan {
    let centerPixelX = longitudeToPixelSpaceX(longitude: centerCoordinate.longitude)
    let centerPixelY = latitudeToPixelSpaceY(latitude: centerCoordinate.latitude)

    let zoomExponent = Double(20 - zoomLevel)
    let zoomScale = pow(2.0, zoomExponent)

    let mapSizeInPixels = mapView.bounds.size
    let scaledMapWidth =  Double(mapSizeInPixels.width) * zoomScale
    let scaledMapHeight = Double(mapSizeInPixels.height) * zoomScale

    let topLeftPixelX = centerPixelX - (scaledMapWidth / 2);
    let topLeftPixelY = centerPixelY - (scaledMapHeight / 2);

    //find delta between left and right longitudes
    let minLng = pixelSpaceXToLongitude(pixelX: topLeftPixelX)
    let maxLng = pixelSpaceXToLongitude(pixelX: topLeftPixelX + scaledMapWidth)
    let longitudeDelta = maxLng - minLng;

    let minLat = pixelSpaceYToLatitude(pixelY: topLeftPixelY)
    let maxLat = pixelSpaceYToLatitude(pixelY: topLeftPixelY + scaledMapHeight)
    let latitudeDelta = -1 * (maxLat - minLat);

    let span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta)
    return span
}

func zoom(toCenterCoordinate centerCoordinate:CLLocationCoordinate2D ,zoomLevel: UInt) {
    let zoomLevel = min(zoomLevel, 20)
    let span = self.coordinateSpan(withMapView: self, centerCoordinate: centerCoordinate, zoomLevel: zoomLevel)
    let region = MKCoordinateRegionMake(centerCoordinate, span)
    self.setRegion(region, animated: true)

  }
}

Usage example:

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = manager.location?.coordinate {
   mapView.zoom(toCenterCoordinate: CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude), zoomLevel: 16)
  }
}
Arie Pinto
  • 1,274
  • 1
  • 11
  • 19
  • Where should I call the locationManager function in? – tejasree vangapalli Dec 26 '18 at 16:14
  • This function is part of the `CLLocationManagerDelegate` protocol, you should implement it in the controller where you are using the user location, it is called automatically as the user updates his location, but this is just an example, you can use the `zoom` method on your mapView where ever suits you right. – Arie Pinto Dec 26 '18 at 16:17