Reputation: 2285
I am using MKMapView on a project and would like to center the map on a coordinate and zoom in. Just like Google maps has:
GMSCameraPosition.camera(withLatitude: -33.8683,
longitude: 151.2086,
zoom: 6)
Is there any Mapkit method for this?
Upvotes: 15
Views: 25864
Reputation: 3805
This works in swift 5, ios 13
Just add the following method to your class:
func zoomAndCenter(on centerCoordinate: CLLocationCoordinate2D, zoom: Double) {
var span: MKCoordinateSpan = mapView.region.span
span.latitudeDelta *= zoom
span.longitudeDelta *= zoom
let region: MKCoordinateRegion = MKCoordinateRegion(center: centerCoordinate, span: span)
mapView.setRegion(region, animated: true)
}
Upvotes: 0
Reputation: 1618
Base on apinho answer. This option follows Swift 5 syntax and allows to use it as an initializer of MKCoordinateRegion, so can be used in other objects beside MKMapView for example in MKMapSnapshotter.
extension MKCoordinateRegion {
init(center: CLLocationCoordinate2D, zoom: UInt, bounds: CGRect) {
let zoom = min(zoom, 20)
let span = MKCoordinateSpan(center: center, zoom: zoom, bounds: bounds)
self.init(center: center, span: span)
}
}
extension MKCoordinateSpan {
static var mercatorOffset: Double {
return 268435456.0
}
static var mercatorRadius: Double {
return 85445659.44705395
}
private static func longitudeToPixelSpaceX(longitude: Double) -> Double {
return round(mercatorOffset + mercatorRadius * longitude * Double.pi / 180.0)
}
private static 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 static func pixelSpaceXToLongitude(pixelX: Double) -> Double {
return ((round(pixelX) - mercatorOffset) / mercatorRadius) * 180.0 / Double.pi
}
private static func pixelSpaceYToLatitude(pixelY: Double) -> Double {
return (Double.pi / 2.0 - 2.0 * atan(exp((round(pixelY) - mercatorOffset) / mercatorRadius))) * 180.0 / Double.pi
}
init(center: CLLocationCoordinate2D, zoom: UInt, bounds: CGRect) {
let centerPixelX = MKCoordinateSpan.longitudeToPixelSpaceX(longitude: center.longitude)
let centerPixelY = MKCoordinateSpan.latitudeToPixelSpaceY(latitude: center.latitude)
let zoomExponent = Double(20 - zoom)
let zoomScale = pow(2.0, zoomExponent)
let mapSizeInPixels = 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 = MKCoordinateSpan.pixelSpaceXToLongitude(pixelX: topLeftPixelX)
let maxLng = MKCoordinateSpan.pixelSpaceXToLongitude(pixelX: topLeftPixelX + scaledMapWidth)
let longitudeDelta = maxLng - minLng
let minLat = MKCoordinateSpan.pixelSpaceYToLatitude(pixelY: topLeftPixelY)
let maxLat = MKCoordinateSpan.pixelSpaceYToLatitude(pixelY: topLeftPixelY + scaledMapHeight)
let latitudeDelta = -1 * (maxLat - minLat)
self.init(latitudeDelta: latitudeDelta, longitudeDelta: longitudeDelta)
}
}
Upvotes: 0
Reputation: 1140
Put the below code in your CustomMapView
subclass of MKMapView
Call is from init
class CustomMapView: MKMapView {
private func zoom() {
let dortmundLocation = CLLocation(latitude: 51.516667, longitude: 7.466667)
let dortmunRegion = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: dortmundLocation.coordinate.latitude, longitude: dortmundLocation.coordinate.longitude), span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
self.setRegion(dortmunRegion, animated: true)
}
}
Upvotes: 6
Reputation: 3523
This is working code tested on swift 4.2
override func viewDidLoad() {
super.viewDidLoad()
let initialLocation = CLLocation(latitude: 28.5761897, longitude: 77.172080)
self.centerMapOnLocation(location: initialLocation)
}
func centerMapOnLocation(location: CLLocation) {
let region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude), span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05))
DispatchQueue.main.async {
self.mapView.setRegion(region, animated: true)
let annotation = MKPointAnnotation()
annotation.coordinate = location.coordinate
self.mapView.addAnnotation(annotation)
}
}
This will load with animation. Hope will help you.
Upvotes: 3
Reputation: 27050
Apinho answer in Swift 4.x
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)
}
}
Upvotes: 3
Reputation: 1127
Swift 3.0
In the MapKit Function didUpdateLocations
:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last as CLLocation? else { return }
let userCenter = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
// Does not have to be userCenter, could replace latitude: and longitude: with any value you would like to center in on
let region = MKCoordinateRegion(center: userCenter, span: MKCoordinateSpan(latitudeDelta: 180, longitudeDelta: 180))
mkView.setRegion(region, animated: true)
}
Note: If you do not want to keep setting the center every time there is a location update, then do the following:
let userCenter = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
// Does not have to be userCenter, could replace latitude: and longitude: with any value you would like to center in on
let region = MKCoordinateRegion(center: userCenter, span: MKCoordinateSpan(latitudeDelta: 180, longitudeDelta: 180))
mkView.setRegion(region, animated: true)
Upvotes: 1
Reputation: 2285
Code based on : http://troybrant.net/blog/2010/01/set-the-zoom-level-of-an-mkmapview/
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 * M_PI / 180.0)
}
private func latitudeToPixelSpaceY(latitude: Double) -> Double {
return round(MERCATOR_OFFSET - MERCATOR_RADIUS * log((1 + sin(latitude * M_PI / 180.0)) / (1 - sin(latitude * M_PI / 180.0))) / 2.0)
}
private func pixelSpaceXToLongitude(pixelX: Double) -> Double {
return ((round(pixelX) - MERCATOR_OFFSET) / MERCATOR_RADIUS) * 180.0 / M_PI;
}
private func pixelSpaceYToLatitude(pixelY: Double) -> Double {
return (M_PI / 2.0 - 2.0 * atan(exp((round(pixelY) - MERCATOR_OFFSET) / MERCATOR_RADIUS))) * 180.0 / M_PI;
}
private func coordinateSpan(withMapView mapView: MKMapView, centerCoordinate: CLLocationCoordinate2D, zoomLevel: UInt) ->MKCoordinateSpan {
let centerPixelX = longitudeToPixelSpaceX(centerCoordinate.longitude)
let centerPixelY = latitudeToPixelSpaceY(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(topLeftPixelX)
let maxLng = pixelSpaceXToLongitude(topLeftPixelX + scaledMapWidth)
let longitudeDelta = maxLng - minLng;
let minLat = pixelSpaceYToLatitude(topLeftPixelY)
let maxLat = pixelSpaceYToLatitude(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)
}
}
Upvotes: 5
Reputation: 3158
Here is a method I use to center your map on a pre-defined CLLocation
using MKCoordinateRegion
.
func centerMapOnLocation(_ location: CLLocation, mapView: MKMapView) {
let regionRadius: CLLocationDistance = 1000
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
regionRadius * 2.0, regionRadius * 2.0)
mapView.setRegion(coordinateRegion, animated: true)
}
Upvotes: 12
Reputation: 1349
You'd create a MKCoordinateRegion object and set that as the region on your MKMapView object.
MKCoordinateRegion mapRegion;
CLLocationCoordinate2D coordinate;
coordinate.latitude = 0;
coordinate.longitude = 0;
mapRegion.center = coordinate;
mapRegion.span.latitudeDelta = 0.2;
mapRegion.span.longitudeDelta = 0.2;
[mapView setRegion:mapRegion animated: YES];
Upvotes: 9