How to zoom in or out a MKMapView in Swift? - ios

Objective
I need my app to zoom in or out a MKMapView.
Code
I thought of animating the value of the altitude of a MKMapCamera. Though, this doesn't zoom in or out the map.
let mapCamera = MKMapCamera()
mapCamera.altitude = 1000000
mapView.camera = mapCamera
UIView.animateWithDuration(10, delay: 0., options: UIViewAnimationOptions.CurveLinear, animations: {
mapCamera.altitude = 6000000
}, completion: {(finished: Bool) in
})
mapView.camera = mapCamera
Question
How do I zoom in or out a MKMapView? Are there any other ways to do so?

Here is an extension based on kevins answer https://stackoverflow.com/a/20129379/1488696
With it you'll be able to zoom in and out as required
extension MKMapView {
// delta is the zoom factor
// 2 will zoom out x2
// .5 will zoom in by x2
func setZoomByDelta(delta: Double, animated: Bool) {
var _region = region;
var _span = region.span;
_span.latitudeDelta *= delta;
_span.longitudeDelta *= delta;
_region.span = _span;
setRegion(_region, animated: animated)
}
}
Use it like so: myMapView.setZoomByDelta(0.5, animated: true)
MKMapCamera is used for 3D maps. So its likely not what you're looking for
Apple Docs
An MKMapCamera object describes a virtual camera that you use to define the appearance of the map. A camera object creates a virtual viewpoint above the map surface and affects how the map renders its tiles and other content. You use a camera object to specify the location of the camera on the map, the compass heading that corresponds to the camera’s viewing direction, the pitch of the camera relative to the map perpendicular, and the camera’s altitude above the map. These factors let you create a map view that is not just flat but offers a more 3D-like experience."

Use the method setRegion:animated:. It takes an MKCoordinateRegion parameter. The region includes a span, which determines the range of north-to-south latitude shown on the screen.

Related

HEREMaps iOS: Zoom to specific point

I need to zoom NMAMapView to specific point inside map bounds. Let's say we have some marker as subview of this map with position pinPoint: CGPoint.
I tried to use transformCenter property of NMAMapView like this:
let transformCenter = CGPoint(x: pinPoint.x / mapView.bounds.width, y: pinPoint.y / mapView.bounds.height) // x and y are in range [0, 1]
mapView.transformCenter = transformCenter
mapView.set(zoomLevel: mapView.zoomLevel + 1, animation: .linear)
But this code zooms map to its frame center, not to pinPoint.
I also tried to zoom map to needed point with code below:
guard let coordinates = mapView.geoCoordinates(from: pinPoint) else {
return
}
mapView.set(coordinates: coordinates, to: pinPoint, animation: .linear, zoomLevel: mapView.zoomLevel + 1)
But this also doesn't work correctly: after zooming, geo coordinates below marker were changed after each zoom step.
Please try to with this code, this code is just for your reference, You need to modify as per your requirements.
// create geo coordinate
let geoCoordCenter = NMAGeoCoordinates(latitude: 49.260327, longitude: -123.115025)
// set map view with geo center
self.mapView.set(geoCenter: geoCoordCenter, animation:NMAMapAnimation.none)
// set zoom level
self.mapView.zoomLevel = 13.2
Please check more example GitHub.

How to move annotation with animation in mapbox map?

I am using mapbox map in my iOS app. I added annotation in mapbox map by using this class MGLPointAnnotation.
Now the problem is i am unable to change its location. This is how i changing annotation location. But it is not moving. I need to remove first old one and again need to add new annotation but i don't want to do this.Please let me know how can i do this.
car.coordinate = CLLocationCoordinate2D(latitude: lat, longitude: lng)
I want the movement of annotation when location changed of annotation with smooth animation.
Also when there is a change in location i'm changing center of my mapbox map with camera. Let me know i am doing right or not.
// Optionally set a starting point.
bMbMapView.setCenter(cord, zoomLevel: 7, direction: bearing, animated: true)
bMbMapView.setDirection(bearing, animated: true)
// Create a camera that rotates around the same center point, rotating 180°.
// `fromDistance:` is meters above mean sea level that an eye would have to be in order to see what the map view is showing.
let camera = MGLMapCamera(lookingAtCenter: cord, fromDistance: 1000, pitch: 7, heading: 90)
// Animate the camera movement over 5 seconds.
bMbMapView.setCamera(camera, withDuration: 1, animationTimingFunction: CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut))
A MGLAnnotationView is a UIView, so you should be able to animate changes with Core Animation: https://github.com/mapbox/mapbox-gl-native/issues/8378#issuecomment-287910768
Another option is to use a style source and layer, then update the source using a timer. This would likely be less smooth than using an animated annotation view.

Swift mkmapview get zoom level, width or radius of visible map area from latitude longitude delta

I am in a confusion, on how to get a zoom level and radius of a visible area of the map (using mapkit mapview).
Here is what I am looking for (either of them or both, as needed) -
Zoom level, is to see at what level of the map is being shown to the users and with that information, I want to display the custom pins in the visible area. If zoom level is high, I need to show the actual logos of some commerce stores as pins. If zoom level is low, I need to show colored dots instead of logos.
As of now, I am using let updatedRadius = (mapView.camera.altitude)/1000 to get altitude of the camera, and if the updatedRadius value is > 25.0, I am showing colored dots. Below 25.0, I show the logos. I am doing this in regionDidChanged
Is this approach correct?
Radius, is to send it as a parameter to my REST API to fetch the list of places within that radius. When user zooms out on the map, visible area increases and so the REST API needs bigger radius to return the places covered in that area.
Ultimately, what should happen is, whenever user zooms out, then the radius changes. I need to send this changed radius to my REST to get an updated list.
What are latitude longtitude deltas, can we get radius/width of visible area using these values?
let latitudeDeltaVal = mapView.region.span.latitudeDelta
let longitudeDeltaVal = mapView.region.span.longitudeDelta
Can someone throw some light on what needs to be done please?
Since you need to call the api when the region changes you need to calculate the radius in mapView's delegate function, RegionDidChange.
func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
let centralLocation = CLLocation(latitude: mapView.centerCoordinate.latitude, longitude: mapView.centerCoordinate.longitude)
self.centralLocationCoordinate = mapView.centerCoordinate
print("Radius - \(self.getRadius(centralLocation))")
}
func getRadius(centralLocation: CLLocation) -> Double{
let topCentralLat:Double = centralLocation.coordinate.latitude - mapView.region.span.latitudeDelta/2
let topCentralLocation = CLLocation(latitude: topCentralLat, longitude: centralLocation.coordinate.longitude)
let radius = centralLocation.distanceFromLocation(topCentralLocation)
return radius / 1000.0 // to convert radius to meters
}
To account for both landscape and portrait orientations, and/or situations where the map orientation is close to Northeast, Northwest, Southwest, Southeast, and to enclose the full screen up to the corners, one should consider both latitudeDelta and longitudeDelta:
func getRadius() -> Double{
let centralLocation = CLLocation(latitude: mapView.region.center.latitude, longitude: mapView.region.center.longitude)
let cornerOfMap = CLLocation(latitude: centralLocation.coordinate.latitude + mapView.region.span.latitudeDelta , longitude: centralLocation.coordinate.longitude + mapView.region.span.longitudeDelta)
let radius = centralLocation.distance(from: cornerOfMap)
return radius / 1000.0 // to convert radius to meters
}

User Current Location on specific position on MAP

MKMapView
CoreLocation
Swift3.0
I have a requirement like this:
Creating an application in which I am getting Lat and Long for various location from webservice . Ploting these locations on map with Custom AnnotationView . Apart from this, I'm showing User Current Location with Custom Image.
Here everything working fine.
Now, when user moves then User Current Location Pin changes its position so there is an important requirement for this, I need to make this Current Location position in such a way that it stick in the bottom of map (just 100 pixel) above from bottom.
I did Some RND and find out few useful links:
Centering MKMapView on spot N-pixels below pin
How can I center my mapview so that the selected pin is not in the middle of the map but in 1/3 of it?
set current location icon lower side in MKMapView
But this not working anymore.
Kindly suggest how can I set user Current Location pin in iOS map in such a way that it always at the bottom of Map (100 pixel above from Bottom)
Required Pin position:
Currently it is showing in other position.
Note - **Dont want Google Map for such functionality.
If you have been using something like this mapView.setUserTrackingMode(.Follow, animated: true) then user location will be always displayed in the center of the map, zoom/pan will be automatically adjusted whenever user location is updated.
You need to disable the UserTrackingMode and then manually adjust the map zoom/pan using func setVisibleMapRect(_ mapRect: MKMapRect, edgePadding insets: UIEdgeInsets, animated animate: Bool) each time whenever user location is changed.
I used following code in similar situation
let annotationPoint = MKMapPointForCoordinate(mapView.userLocation.coordinate);
var zoomRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 1, 1);
annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
let pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 1, 1);
zoomRect = MKMapRectUnion(zoomRect, pointRect);
mapView.setVisibleMapRect(zoomRect, edgePadding: UIEdgeInsetsMake(40, 50, 160, 50), animated: true)
p.s. edgePadding is your friend in this case.
Here is the trick to use to position the map in such a way that UserLocation pin gets adjusted automatically :
func setUserLocationOnLowerPositiononMap(coordinate: CLLocationCoordinate2D) {
var region = MKCoordinateRegion(center: coordinate, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
region.center = coordinate
self.map.setRegion(region, animated: true)
//self.map.moveCenterByOffSet(offSet: CGPoint(x: 0, y: -130), coordinate: coordinate)
self.map.moveCenterByOffSet(offSet: CGPoint(x: 0, y: SCREEN_HEIGHT - SCREEN_HEIGHT * 4/3 + 0 ), coordinate: coordinate)
}

Tilt map in Mapkit programmatically using Swift

I'd like to tilt the map at startup. (Same as the user does when scrolling up or down with 2 fingers)
Is this possible using Swift?
MKMapView Class Reference : http://goo.gl/djHXPn
Look at the camera property :
A camera object defines a point above the map’s surface from which to view the map. Applying a camera to a map has the effect of giving the map a 3D-like appearance. You can use a camera to rotate the map so that it is oriented to match the user’s heading or to apply a pitch angle to tilt the plane of the map.
Assigning a new camera to this property updates the map immediately and without animating the change. If you want to animate changes in camera position, use the setCamera:animated: method instead.
You must not set this property to nil. To restore the map to a flat appearance, apply a camera with a pitch angle of 0, which yields a camera looking straight down onto the map surface.
Try to create and set a camera (animated or not).
Edit :
I tried myself. Here is an example of how to use it :
let userCoordinate = CLLocationCoordinate2D(latitude: 58.592725, longitude: 16.185962)
let eyeCoordinate = CLLocationCoordinate2D(latitude: 58.571647, longitude: 16.234660)
let mapCamera = MKMapCamera(lookingAtCenterCoordinate: userCoordinate, fromEyeCoordinate: eyeCoordinate, eyeAltitude: 400.0)
let annotation = MKPointAnnotation()
annotation.setCoordinate(userCoordinate)
mapView.addAnnotation(annotation)
mapView.setCamera(mapCamera, animated: true)
You'll have to find your right eyeCoordinate depending on your location and tilt effect you want to have.
Swift 4
This is an easier way: you can set distance, pitch and heading:
let mapCamera = MKMapCamera(lookingAtCenter: userCoordinate, fromDistance: 10000, pitch: 65, heading: 0)
map.setCamera(mapCamera, animated: true)

Resources