Skip to content

Instantly share code, notes, and snippets.

@varyP
Last active February 10, 2020 02:49
Show Gist options
  • Save varyP/93da6fa0d63a7249332e2b1c1eb42b8e to your computer and use it in GitHub Desktop.
Save varyP/93da6fa0d63a7249332e2b1c1eb42b8e to your computer and use it in GitHub Desktop.
Swift5 implementation to get radius from MKMapView's current zoomed in region & zoom-pan to any coordinate with animation.
// Created by Varun Parakh on 09/04/19 via Daniel.Burke (https://gist.github.com/d2burke/ad29811b07ae31b378ff)
/*
Have these defined in your global constants.
let mercatorRadius = 85445659.44705395
let maxGoogleZoomLevels = 20
let mercatorOffset = 268435456.0
*/
//
// MKMapView+Ext.swift
//
import Foundation
import MapKit
extension MKMapView {
private func longitudeToPixelSpaceX(longitude: Double) -> Double {
return round(mercatorOffset + mercatorRadius * longitude * Double.pi / 180.0)
}
private func latitudeToPixelSpaceY(latitude: Double) -> Double {
return round(mercatorOffset - mercatorRadius * 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) - mercatorOffset) / mercatorRadius) * 180.0 / Double.pi
}
private func pixelSpaceYToLatitude(pixelY: Double) -> Double {
return (Double.pi / 2.0 - 2.0 * atan(exp((round(pixelY) - mercatorOffset / mercatorRadius) ))) * 180.0 / Double.pi
}
private func coordinateSpan(withMapView mapView: MKMapView, centerCoordinate: CLLocationCoordinate2D, zoomLevel: Double) -> 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 = MKCoordinateSpan(latitudeDelta: latitudeDelta, longitudeDelta: longitudeDelta)
return span
}
func zoom(toCenterCoordinate centerCoordinate: CLLocationCoordinate2D, zoomLevel: Double, animated: Bool) {
let zoomLevel = min(zoomLevel, Double(maxGoogleZoomLevels))
let span = self.coordinateSpan(withMapView: self, centerCoordinate: centerCoordinate, zoomLevel: zoomLevel)
let region = MKCoordinateRegion(center: centerCoordinate, span: span)
self.setRegion(region, animated: animated)
}
func zoomLevel() -> Double {
let longitudeDelta = self.region.span.longitudeDelta
let mapWidthInPixels = self.bounds.size.width
let zoomScale = CGFloat(longitudeDelta * mercatorRadius * Double.pi) / (180.0 * mapWidthInPixels)
var zoomer = CGFloat(maxGoogleZoomLevels) - log2( zoomScale )
//Zoom can not be less than 0
zoomer = max(zoomer, 0)
return Double(zoomer)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment