swift: how to draw an arc on map via MapKit? - ios

I have to draw an arc having two angles, center point and radius as input. I use UIBezierPath, but overlay isn't added to the map. Here's my code:
func calculateByArc()
{
let startingAzimuth = Double(upperLimitTextBox.text!)
let endingAzimuth = Double(upperLimitUomTextBox.text!)
let radius = Double(lowerLimitTextBox.text!)
let latitude = Double(lowerLimitUomTextBox.text!)
let longitude = Double(textField5.text!)
let clockwise = clockwiseSwitch.isOn ? true : false
let qwe = CLLocationCoordinate2DMake(latitude!,longitude!)
let asd = Map.convert(qwe, toPointTo: Map)
let test = Map.convert(asd, toCoordinateFrom: Map)
print("test lat: " + String(test.latitude))
print("test lon: " + String(test.longitude))
let path = UIBezierPath(arcCenter: Map.convert (qwe, toPointTo: mapController.Map), radius: CGFloat(radius!), startAngle: CGFloat(Helper.toRad(startingAzimuth!)), endAngle: CGFloat(Helper.toRad(endingAzimuth!)) , clockwise: clockwise)
let arc = MKCircle(center: CLLocationCoordinate2DMake(latitude!, longitude!), radius: radius!)
arc.accessibilityPath = path
Map.add(arc)
}
and my mapView:
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer
{
if overlay is MKCircle
{
print("overlay latitude: "+String(overlay.coordinate.latitude))
print("overlay longitude: "+String(overlay.coordinate.longitude))
let circleOverlay = overlay as! MKCircle
if(circleOverlay.accessibilityPath != nil)
{
let arcRenderer = MKOverlayPathRenderer()
arcRenderer.path = circleOverlay.accessibilityPath?.cgPath
arcRenderer.strokeColor = UIColor.red
arcRenderer.lineWidth = 10
arcRenderer.alpha = 0.3
return arcRenderer
}
let circle = MKCircleRenderer(overlay: overlay)
circle.strokeColor = UIColor.black
circle.fillColor = UIColor(red: 255, green: 0, blue: 0, alpha: 0.1)
circle.lineWidth = 1
circle.alpha = 0.3
return circle
}
}
I guess it's because i don't properly convert CLLocationCoordinate2D to CGPoint, because a couple of weeks ago i managed to draw an arc, but with wrong coordinates(can't remember how i did that).

Is this what you are looking for http://nshipster.com/mkgeodesicpolyline/ ?

Related

Swift 3 - Line is getting thicker in MKMapView

I am using MKMapView and PolyLine concept to draw a line.But when the line is drawn line is getting thicker when it goes ahead.I want a single line throughout the route.
My code:-
func assigArray() {
if self.lat.count == self.lon.count {
for i in 0 ..< self.lat.count {
let destination = CLLocationCoordinate2DMake(self.lat[i], self.lon[i])
coordinateArray.append(destination)
}
self.mapp()
}
}
func mapp() {
let coords2 = CLLocationCoordinate2D(latitude: lat.last!, longitude: lon.last!)
let testline = MKPolyline(coordinates: coordinateArray, count: coordinateArray.count)
//Add `MKPolyLine` as an overlay.
map.add(testline)
map.delegate = self
map.centerCoordinate = coords2
map.region = MKCoordinateRegion(center: coords2, span: MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02))
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.strokeColor = UIColor.red
renderer.lineWidth = 2.0
return renderer
}

Changing the stroke color of map overlay on tap

I have a map view and I am generating a bunch of mkcircle overlays. These have a stroke width and fill color.
I also have a tap gesture set up that determines if the tap is on one of the mkcircles. What I would like to do now is change the stroke width and fill color so the user knows which mkcircle was tapped and then change it back on any other tap.
The code I have is below.
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let circleRenderer = MKCircleRenderer(overlay: overlay)
circleRenderer.fillColor = UIColor.blue.withAlphaComponent(0.1)
circleRenderer.strokeColor = UIColor.blue
circleRenderer.lineWidth = 2
return circleRenderer
}
func handleMapTap(_ gestureReconizer: UITapGestureRecognizer) {
let tapPoint = gestureReconizer.location(in: mapView)
let tapCoordinate = mapView.convert(tapPoint, toCoordinateFrom: mapView)
let point = MKMapPointForCoordinate(tapCoordinate)
if mapView.overlays.count > 0 {
for overlay: MKOverlay in polygonArray {
if (overlay is MKCircle) {
let circle = overlay
let circleRenderer = (mapView.renderer(for: circle) as! MKCircleRenderer)
let datapoint = circleRenderer.point(for: point)
circleRenderer.invalidatePath()
if circleRenderer.path.contains(datapoint) {
let circleIndex = polygonArray.index{$0 === circle}!
print(circleIndex)
}
}
}
}
}
I have done some searching but I have not been able to find a solution yet. I am able to get the circleIndex of the tapped circle.
Any guidance is appreciated.
Just in case anyone else comes across this here is the answer which was actually pretty easy in the end.
func handleMapTap(_ gestureReconizer: UITapGestureRecognizer) {
let tapPoint = gestureReconizer.location(in: mapView)
let tapCoordinate = mapView.convert(tapPoint, toCoordinateFrom: mapView)
let point = MKMapPointForCoordinate(tapCoordinate)
if mapView.overlays.count > 0 {
for overlay: MKOverlay in polygonArray {
if (overlay is MKCircle) {
let circle = overlay
let circleRenderer = (mapView.renderer(for: circle) as! MKCircleRenderer)
let datapoint = circleRenderer.point(for: point)
circleRenderer.invalidatePath()
circleRenderer.fillColor = UIColor.blue.withAlphaComponent(0.1)
circleRenderer.strokeColor = UIColor.blue
if circleRenderer.path.contains(datapoint) {
circleRenderer.fillColor = UIColor.black
circleRenderer.strokeColor = UIColor.black
let circleIndex = polygonArray.index{$0 === circle}!
print(circleIndex)
}
}
}
}
}

How to get animated polyline route in GMSMapView, so that it move along with map when map is moved?

I have created animated polyline like CAShapeLayer by following code, I have added CAShapeLayer as sublayer to GMSMapiew but, if I move the map the layer won't moves. where to add the layer, so that it move along with map?
func layer(from path: GMSPath) -> CAShapeLayer {
let breizerPath = UIBezierPath()
let firstCoordinate: CLLocationCoordinate2D = path.coordinate(at: 0)
breizerPath.move(to: self.mapView.projection.point(for: firstCoordinate))
for i in 1 ..< Int((path.count())){
print(path.coordinate(at: UInt(i)))
let coordinate: CLLocationCoordinate2D = path.coordinate(at: UInt(i))
breizerPath.addLine(to: self.mapView.projection.point(for: coordinate))
}
let shapeLayer = CAShapeLayer()
shapeLayer.path = breizerPath.reversing().cgPath
shapeLayer.strokeColor = UIColor.green.cgColor
shapeLayer.lineWidth = 4.0
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineJoin = kCALineJoinRound
shapeLayer.lineCap = kCALineCapRound
shapeLayer.cornerRadius = 5
return shapeLayer
}
func animatePath(_ layer: CAShapeLayer) {
let pathAnimation = CABasicAnimation(keyPath: "strokeEnd")
pathAnimation.duration = 6
//pathAnimation.delegate = self
pathAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
pathAnimation.fromValue = Int(0.0)
pathAnimation.toValue = Int(1.0)
pathAnimation.repeatCount = 100
layer.add(pathAnimation, forKey: "strokeEnd")
}
Added to GoogleMapView by
let shapelayer: CAShapeLayer = self.layer(from: path!)
self.animatePath(shapelayer)
self.mapView.layer.addSublayer(shapelayer)
SWIFT
Declartion
var polyline = GMSPolyline()
var animationPolyline = GMSPolyline()
var path = GMSPath()
var animationPath = GMSMutablePath()
var i: UInt = 0
var timer: Timer!
To Darw Route
func drawRoute(routeDict: Dictionary<String, Any>) {
let routesArray = routeDict ["routes"] as! NSArray
if (routesArray.count > 0)
{
let routeDict = routesArray[0] as! Dictionary<String, Any>
let routeOverviewPolyline = routeDict["overview_polyline"] as! Dictionary<String, Any>
let points = routeOverviewPolyline["points"]
self.path = GMSPath.init(fromEncodedPath: points as! String)!
self.polyline.path = path
self.polyline.strokeColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5)
self.polyline.strokeWidth = 3.0
self.polyline.map = self.mapView
self.timer = Timer.scheduledTimer(timeInterval: 0.003, target: self, selector: #selector(animatePolylinePath), userInfo: nil, repeats: true)
}
}
To Animate Path
func animatePolylinePath() {
if (self.i < self.path.count()) {
self.animationPath.add(self.path.coordinate(at: self.i))
self.animationPolyline.path = self.animationPath
self.animationPolyline.strokeColor = UIColor.black
self.animationPolyline.strokeWidth = 3
self.animationPolyline.map = self.mapView
self.i += 1
}
else {
self.i = 0
self.animationPath = GMSMutablePath()
self.animationPolyline.map = nil
}
}
Don't forgot to stop timer in viewWillDisappear
self.timer.invalidate()
Output
I am create GMSPath animation with path coordinate
Objective C
interface
#interface MapWithTracking ()
#property (weak, nonatomic) IBOutlet GMSMapView *mapView;
#property (nonatomic,strong) GMSMutablePath *path2;
#property (nonatomic,strong)NSMutableArray *arrayPolylineGreen;
#property (nonatomic,strong) GMSPolyline *polylineBlue;
#property (nonatomic,strong) GMSPolyline *polylineGreen;
#end
implementation
-(void)viewDidLoad {
_arrayPolylineGreen = [[NSMutableArray alloc] init];
_path2 = [[GMSMutablePath alloc]init];
}
Get a GMSPath and create a blue polyline.
-(void)createBluePolyline(GMSPath *path) {
// Here create a blue poly line
_polylineBlue = [GMSPolyline polylineWithPath:path];
_polylineBlue.strokeColor = [UIColor blueColor];
_polylineBlue.strokeWidth = 3;
_polylineBlue.map = _mapView;
// animate green path with timer
[NSTimer scheduledTimerWithTimeInterval:0.003 repeats:true block:^(NSTimer * _Nonnull timer) {
[self animate:path];
}];
}
Animate a Green Polyline
Adding coordinate to path 2 and assign to map
-(void)animate:(GMSPath *)path {
dispatch_async(dispatch_get_main_queue(), ^{
if (i < path.count) {
[_path2 addCoordinate:[path coordinateAtIndex:i]];
_polylineGreen = [GMSPolyline polylineWithPath:_path2];
_polylineGreen.strokeColor = [UIColor greenColor];
_polylineGreen.strokeWidth = 3;
_polylineGreen.map = _mapView;
[arrayPolylineGreen addObject:_polylineGreen];
i++;
}
else {
i = 0;
_path2 = [[GMSMutablePath alloc] init];
for (GMSPolyline *line in arrayPolylineGreen) {
line.map = nil;
}
}
});
}
This is an adaptation of the code from Elangovan
The changes that I did was to remove the var from the class to be just in the function and also removed the #selector that is no longer need in iOS >= 10.
var timerAnimation: Timer!
var mapView:GMSMapView?
func drawRoute(encodedString: String, animated: Bool) {
if let path = GMSMutablePath(fromEncodedPath: encodedString) {
let polyline = GMSPolyline(path: path)
polyline.strokeWidth = 3.0
polyline.strokeColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5)
polyline.map = Singleton.shared.getMapView()
if(animated){
self.animatePolylinePath(path: path)
}
}
}
func animatePolylinePath(path: GMSMutablePath) {
var pos: UInt = 0
var animationPath = GMSMutablePath()
let animationPolyline = GMSPolyline()
self.timerAnimation = Timer.scheduledTimer(withTimeInterval: 0.003, repeats: true) { timer in
pos += 1
if(pos >= path.count()){
pos = 0
animationPath = GMSMutablePath()
animationPolyline.map = nil
}
animationPath.add(path.coordinate(at: pos))
animationPolyline.path = animationPath
animationPolyline.strokeColor = UIColor.yellow
animationPolyline.strokeWidth = 3
animationPolyline.map = self.mapView
}
}
func stopAnimatePolylinePath() {
self.timerAnimation.invalidate()
}
Move the layer whenever the map moves by implementing the delegate mapView:didChangeCameraPosition:.
You need to use GMSPolyline for this. Create a GMSPolyline instance, set your GMSMapView instance to be it's parent map.
GMSPolyline* routeOverlay = // config
routeOverlay.map = // my GMSMapView instance
That's all. You don't need to do anything extra to make it move with the map camera movement. It does that automatically.
You can create a variable for shapeLayer and use the GMSMapViewDelegate methods
mapView(_ mapView: GMSMapView, willMove gesture: Bool) and
mapView(_ mapView: GMSMapView, idleAt position: GMSCameraPosition) to add and remove the layer from the map. There are two downsides to this approach, first is that the layer doesn't animate when the map is being dragged(moved) and second downside is that the layer always sits on top of all other map elements like markers, road names, POIs etc. I couldn't find a way to add this layer as a sublayer directly to the ground overlay. You can find the full code below:
var polyLineShapeLayer:CAShapeLayer?
var layerAdded = false
var path = GMSPath()
var polyLine:GMSPolyline!
// Add regular polyline to the map
func addPolyLineWithEncodedStringInMap(_ encodedString:String) {
self.polyLine = GMSPolyline(path: self.path)
polyLine.strokeWidth = 3.8
self.polyLine.strokeColor = .black
polyLine.map = googleMapView
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {
self.addPolyLineShapeLayerToMapView()
self.layerAdded = true
}
}
// Add CAshapeLayer to map
func layer(from path: GMSPath) -> CAShapeLayer {
let breizerPath = UIBezierPath()
let firstCoordinate: CLLocationCoordinate2D = path.coordinate(at: 0)
breizerPath.move(to: self.googleMapView.projection.point(for: firstCoordinate))
for i in 1 ..< Int((path.count())){
print(path.coordinate(at: UInt(i)))
let coordinate: CLLocationCoordinate2D = path.coordinate(at: UInt(i))
breizerPath.addLine(to: self.googleMapView.projection.point(for: coordinate))
}
let shapeLayer = CAShapeLayer()
shapeLayer.path = breizerPath.cgPath
shapeLayer.strokeColor = UIColor.lightGray.withAlphaComponent(0.8).cgColor
shapeLayer.lineWidth = 4.0
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineJoin = kCALineJoinRound
shapeLayer.lineCap = kCALineCapRound
shapeLayer.cornerRadius = 5
return shapeLayer
}
func animatePath(_ layer: CAShapeLayer) {
let pathAnimation = CABasicAnimation(keyPath: "strokeEnd")
pathAnimation.duration = 2
pathAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
pathAnimation.fromValue = Int(0.0)
pathAnimation.toValue = Int(1.0)
pathAnimation.repeatCount = 200
layer.add(pathAnimation, forKey: "strokeEnd")
}
func addPolyLineShapeLayerToMapView(){
polyLineShapeLayer = self.layer(from: self.path)
if let polyLineShapeLayer = polyLineShapeLayer{
self.animatePath(polyLineShapeLayer)
self.googleMapView.layer.addSublayer(polyLineShapeLayer)
polyLineShapeLayer.zPosition = 0
}
}
// Delegate methods to control the polyline
// whenever map is about to move, if layer is already added, remove the layer from superLayer
func mapView(_ mapView: GMSMapView, willMove gesture: Bool) {
if layerAdded{
DispatchQueue.main.async {
self.polyLineShapeLayer?.removeFromSuperlayer()
self.polyLineShapeLayer = nil
}
}
}
// when map is idle again(var layerAdded:bool ensures that additional layer is not added initially when the delegate method is fired) add new instance of polylineShapeLayer to the map with current projected coordinates.
func mapView(_ mapView: GMSMapView, idleAt position: GMSCameraPosition) {
if self.layerAdded{
self.addPolyLineShapeLayerToMapView()
}
}

MKPolyline draws strange relics when zooming

I draw MKPolyline on map. Sometimes when I zoom a couple of times, something like this is left on the map:
Is it something specific for iOS maps that I cannot improve?
Or maybe with my drawing method something is wrong?
my MKPolyline class:
class MulticolorPolylineSegment: MKPolyline {
var color: UIColor?
class func colorSegments(forLocations locations: [Location]) -> [MulticolorPolylineSegment] {
var colorSegments = [MulticolorPolylineSegment]()
let red = (r: 254.0/255.0, g: 200.0 / 255.0, b: 20.0/255.0)
// RGB for Yellow (middle)
let yellow = (r: 254.0/255.0, g: 200.0 / 255.0, b: 20.0/255.0)
// RGB for Green (fastest)
let green = (r: 254.0/255.0, g: 200.0 / 255.0, b: 20.0/255.0)
let (speeds, minSpeed, maxSpeed) = allSpeeds(forLocations: locations)
// now knowing the slowest+fastest, we can get mean too
let meanSpeed = (minSpeed + maxSpeed)/2
for i in 1..<locations.count {
let l1 = locations[i-1]
let l2 = locations[i]
print("dsd")
var coords = [CLLocationCoordinate2D]()
coords.append(CLLocationCoordinate2D(latitude: l1.latitude, longitude: l1.longitude))
coords.append(CLLocationCoordinate2D(latitude: l2.latitude, longitude: l2.longitude))
let speed = speeds[i-1]
var color = UIColor.black
if speed < minSpeed { // Between Red & Yellow
let ratio = (speed - minSpeed) / (meanSpeed - minSpeed)
let r = CGFloat(red.r + ratio * (yellow.r - red.r))
let g = CGFloat(red.g + ratio * (yellow.g - red.g))
let b = CGFloat(red.r + ratio * (yellow.r - red.r))
color = UIColor(red: r, green: g, blue: b, alpha: 1)
}
else { // Between Yellow & Green
let ratio = (speed - meanSpeed) / (maxSpeed - meanSpeed)
let r = CGFloat(yellow.r + ratio * (green.r - yellow.r))
let g = CGFloat(yellow.g + ratio * (green.g - yellow.g))
let b = CGFloat(yellow.b + ratio * (green.b - yellow.b))
color = UIColor(red: r, green: g, blue: b, alpha: 1)
}
let segment = MulticolorPolylineSegment(coordinates: &coords, count: coords.count)
segment.color = color
colorSegments.append(segment)
}
return colorSegments
}
fileprivate class func allSpeeds(forLocations locations: [Location]) -> (speeds: [Double], minSpeed: Double, maxSpeed: Double) {
// Make Array of all speeds. Find slowest and fastest
var speeds = [Double]()
var minSpeed = DBL_MAX
var maxSpeed = 0.0
for i in 1..<locations.count {
let l1 = locations[i-1]
let l2 = locations[i]
let cl1 = CLLocation(latitude: l1.latitude, longitude: l1.longitude)
let cl2 = CLLocation(latitude: l2.latitude, longitude: l2.longitude)
let distance = cl2.distance(from: cl1)
let time = l2.timestamp.timeIntervalSince(l1.timestamp as Date)
let speed = distance/time
minSpeed = min(minSpeed, speed)
maxSpeed = max(maxSpeed, speed)
speeds.append(speed)
}
return (speeds, minSpeed, maxSpeed)
}
}
View Controller methods implementation
#objc(mapView:rendererForOverlay:) func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
let polyline = overlay as! MulticolorPolylineSegment
let renderer = MKPolylineRenderer(polyline: polyline)
renderer.strokeColor = polyline.color
renderer.lineWidth = 10
return renderer
}
func polyline() -> MKPolyline {
var coords = [CLLocationCoordinate2D]()
let locations = self.locations
for location in locations {
coords.append(CLLocationCoordinate2D(latitude: location.latitude,
longitude: location.longitude))
print("dodalo")
}
return MKPolyline(coordinates: &coords, count: run.locations.count)
}

How to set zoom level or radius in map view?

Good day. I would like to know how to set like a radius of 1km on a current location on a MapView with
mapView.showsUserLocation = true
Is that possible? Thank you.
You can set "zoom level" by MKCoordinateSpanMake.
Try with this:
mapView.setRegion(MKCoordinateRegion(center: CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude), span: MKCoordinateSpanMake(0.05, 0.05)), animated: true)
Not my code. Maybe it can help you
extension MKMapView {
private var MERCATOR_OFFSET: Double {
get {
return 268435456
}
}
private var MERCATOR_RADIUS: Double {
get {
return 85445659.44705395
}
}
private var MAX_ZOOM_LEVEL: Double {
get {
return 19
}
}
// MARK: - Private functions
private func longitudeToPixelSpaceX (longitude: Double) -> Double {
return round(MERCATOR_OFFSET + MERCATOR_RADIUS * longitude * M_PI / 180.0)
}
private func latitudeToPixelSpaceY (latitude: Double) -> Double {
let a = 1 + sinf(Float(latitude * M_PI) / 180.0)
let b = 1.0 - sinf(Float(latitude * M_PI / 180.0)) / 2.0
return round(MERCATOR_OFFSET - MERCATOR_RADIUS * Double(logf(a / b)))
}
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 coordinateSpanWithMapView(mapView: MKMapView, centerCoordinate: CLLocationCoordinate2D, andZoomLevel zoomLevel:Int) -> MKCoordinateSpan {
// convert center coordiate to pixel space
let centerPixelX = self.longitudeToPixelSpaceX(centerCoordinate.longitude)
let centerPixelY = self.latitudeToPixelSpaceY(centerCoordinate.latitude)
// determine the scale value from the zoom level
let zoomExponent = 20 - zoomLevel
let zoomScale = CGFloat(pow(Double(2), Double(zoomExponent)))
// scale the map’s size in pixel space
let mapSizeInPixels = mapView.bounds.size
let scaledMapWidth = mapSizeInPixels.width * zoomScale
let scaledMapHeight = mapSizeInPixels.height * zoomScale
// figure out the position of the top-left pixel
let topLeftPixelX = CGFloat(centerPixelX) - (scaledMapWidth / 2)
let topLeftPixelY = CGFloat(centerPixelY) - (scaledMapHeight / 2)
// find delta between left and right longitudes
let minLng: CLLocationDegrees = self.pixelSpaceXToLongitude(Double(topLeftPixelX))
let maxLng: CLLocationDegrees = self.pixelSpaceXToLongitude(Double(topLeftPixelX + scaledMapWidth))
let longitudeDelta: CLLocationDegrees = maxLng - minLng
// find delta between top and bottom latitudes
let minLat: CLLocationDegrees = self.pixelSpaceYToLatitude(Double(topLeftPixelY))
let maxLat: CLLocationDegrees = self.pixelSpaceYToLatitude(Double(topLeftPixelY + scaledMapHeight))
let latitudeDelta: CLLocationDegrees = -1 * (maxLat - minLat)
// create and return the lat/lng span
let span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta)
return span
}
// MARK: - Public Functions
func setCenterCoordinate(centerCoordinate: CLLocationCoordinate2D, zoomLevel: Int, animated: Bool) {
// clamp large numbers to 28
let zoom = min(zoomLevel, 28)
// use the zoom level to compute the region
let span = self.coordinateSpanWithMapView(self, centerCoordinate:centerCoordinate, andZoomLevel:zoom)
let region = MKCoordinateRegionMake(centerCoordinate, span)
// set the region like normal
self.setRegion(region, animated:animated)
}
func getZoomLevel() -> Int {
let longitudeDelta = self.region.span.longitudeDelta
let mapWidthInPixels = self.bounds.size.width*2 //2 is for retina display
let zoomScale = longitudeDelta * MERCATOR_RADIUS * M_PI / Double((180.0 * mapWidthInPixels))
var zoomer = MAX_ZOOM_LEVEL - log2(zoomScale)
if zoomer < 0 {
zoomer = 0
}
zoomer = round(zoomer)
return Int(zoomer)
}
}
Use like
mapView.setCenterCoordinate(mapView.centerCoordinate, zoomLevel: 17, animated: true)
here i am adding circle from current location to radius of 1 km and area of map displaya about 6 km square. i think it will help you.
// adding circle as overlay
func addRadiusCircle(location: CLLocation){
self.mapView.delegate = self
//radius of 1000 meters
let circle = MKCircle(centerCoordinate: location.coordinate, radius: 1000 as CLLocationDistance)
self.mapView.addOverlay(circle)
}
//circle design and coloring
func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
let circle = MKCircleRenderer(overlay: overlay)
if overlay is MKCircle {
circle.strokeColor = UIColor.blackColor()
circle.fillColor = UIColor(red: 235/255, green: 174/255, blue: 13/255, alpha:0.3)
circle.lineWidth = 1
}
return circle
}
// initial area to display on map
func centerMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
6000, 6000)
mapView.setRegion(coordinateRegion, animated: true)
}

Resources