Skip to content

Instantly share code, notes, and snippets.

@sora0077
Forked from appsandwich/MKMapView+Extensions
Last active November 24, 2020 14:41
Show Gist options
  • Save sora0077/bbcdfd057287b44b6c2332fea92f5dbb to your computer and use it in GitHub Desktop.
Save sora0077/bbcdfd057287b44b6c2332fea92f5dbb to your computer and use it in GitHub Desktop.
Get & set the zoom level of a MKMapView
import MapKit
// http://troybrant.net/blog/2010/01/set-the-zoom-level-of-an-mkmapview/
private let mercadorRadius: Double = 85445659.44705395
private let mercadorOffset: Double = 268435456
private func longitudeToPixelSpaceX(longitude: Double) -> Double {
return round(mercadorOffset + mercadorRadius * longitude * .pi / 180.0);
}
private func latitudeToPixelSpaceY(latitude: Double) -> Double {
return round(mercadorOffset - mercadorRadius * log((1 + sin(latitude * .pi / 180.0)) / (1 - sin(latitude * .pi / 180.0))) / 2.0);
}
private func pixelSpaceXToLongitude(pixelX: Double) -> Double {
return ((round(pixelX) - mercadorOffset) / mercadorRadius) * 180.0 / .pi;
}
private func pixelSpaceYToLatitude(pixelY: Double) -> Double {
return (.pi / 2.0 - 2.0 * atan(exp((round(pixelY) - mercadorOffset) / mercadorRadius))) * 180.0 / .pi;
}
private func coordinateSpan(with mapView: MKMapView, center: CLLocationCoordinate2D, zoomLevel: Double) -> MKCoordinateSpan {
// convert center coordiate to pixel space
let centerPixelX = longitudeToPixelSpaceX(longitude: center.longitude)
let centerPixelY = latitudeToPixelSpaceY(latitude: center.latitude)
// determine the scale value from the zoom level
let zoomExponent = 20 - zoomLevel
let zoomScale = pow(2, zoomExponent)
// scale the map’s size in pixel space
let mapSizeInPixels = mapView.bounds.size
let scaledMapWidth = Double(mapSizeInPixels.width) * zoomScale
let scaledMapHeight = Double(mapSizeInPixels.height) * zoomScale
// figure out the position of the top-left pixel
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
// find delta between top and bottom latitudes
let minLat = pixelSpaceYToLatitude(pixelY: topLeftPixelY)
let maxLat = pixelSpaceYToLatitude(pixelY: topLeftPixelY + scaledMapHeight)
let latitudeDelta = -1 * (maxLat - minLat)
// create and return the lat/lng span
return MKCoordinateSpan(latitudeDelta: latitudeDelta, longitudeDelta: longitudeDelta)
}
extension MKMapView {
func setCenter(_ coordinate: CLLocationCoordinate2D, zoomLevel: Int, animated: Bool) {
var zoomLevel = zoomLevel
// clamp large numbers to 28
zoomLevel = min(zoomLevel, 28);
// use the zoom level to compute the region
let span = coordinateSpan(with: self, center: coordinate, zoomLevel: Double(zoomLevel))
let region = MKCoordinateRegion(center: coordinate, span: span)
// set the region like normal
setRegion(region, animated: animated)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment