-
-
Save sora0077/bbcdfd057287b44b6c2332fea92f5dbb to your computer and use it in GitHub Desktop.
Get & set the zoom level of a MKMapView
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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