Animate With a Map Camera

In an earlier tip, I showed you how to make a map in iPad Playgrounds. Let’s learn how to animate those maps, doing a flyover of Michigan avenue in Chicago from The former home of Chess Records at 2120 South Michigan Avenue (immortalized in the Rolling Stones song) and past Grant park to North Avenue Beach, center stage for The Chicago Air and Water show and several major beach volleyball tournaments. Since this is a north-south street, it makes it easy to change only the latitude to get the flyover. Download the starter file, where I’ve set up a map of Chicago.
I launched the map with our stating location. If you don’t know how to do this, check the course Advanced iOS Development: MapKit and Core Location for more. You’ll want a starting location to give the map time to do some updating before you start the animation. I made this map a standard map, which will run faster that satellite flyovers. I also made a button to start the animation, and we’ll do our work in the method it calls, animate.
I’ll initialize a variable currentLatitude to create our position for the camera

var currentLatitude = startlocation.latitude

And set an small increment of degrees latitude to move

let increment = 0.00005

Add a timer to execute immediately. I’ll set the time interval to repeat for 30 frames per second, or one frame every 1/30th of a second.

let timer = Timer.scheduledTimer(withTimeInterval: 1.0/30.0, repeats: true, block: { (timer) in

In the closure for the timer, I’ll increment the camera one degree:

self.currentLatitude += increment

I’ll check if we hit a latitude for North Avenue beach. When we do, we’ll stop the timer with invalidate.

if self.currentLatitude >= endLatitude {
   timer.invalidate()
}

Finally I’ll update the camera

self.mapview.camera.centerCoordinate.latitude = currentLatitude

Run this on an iPhone 8 simulator. You see it takes a second to get the image together. That’s the reason for the button. There will be a delay while the system tries to render the city. As you run, you’ll notice the animation is a bit jerky. Stop the app.

Simulators are horrible for running run map related apps. They cannot render fast enough. If you run this on an actual device, you’ll get a much smoother animation.

I made the simplest type of animation here, but there are lots of variations. I find that the standard mode work the best. You can use .satelliteflyover, but it takes a so long to render change the frame rate to 10-15 frames per second. You may also see some errors where you bounce around due to “turbulence” as altitude isusbject to rounding error.

Even with those limitations, using animation over areas can lead to some exciting effects.

The Whole Code

//
//  ViewController.swift
//  ChicagoFlyover
//
//  A exercise file for iOS Development Tips Weekly
//  by Steven Lipton (C)2018, All rights reserved
//  For videos go to http://bit.ly/TipsLinkedInLearning
//  For code go to http://bit.ly/AppPieGithub
//

import UIKit
import MapKit

class ViewController:UIViewController{

    @IBOutlet weak var mapview: MKMapView!
    var timer = Timer()
    let startlocation = CLLocationCoordinate2DMake(41.851, -87.6238) //23rd and S. Michigan
    let endLatitude = 41.91 //North Avenue Beach

    @IBAction func flyOverChicago(_ sender: UIButton) {
        animate()
    }

    func startMapView(){
        mapview.frame = view.frame
        let mapcamera = MKMapCamera(lookingAtCenter: startlocation, fromDistance: 500, pitch: 60, heading: 0.0)
        mapview.mapType = .standard
        mapview.camera = mapcamera
    }

    func animate(){
        var currentLatitude = startlocation.latitude
        let increment = 0.00005
        let _ = Timer.scheduledTimer(withTimeInterval: (1.0/30.0), repeats: true) { (timer) in
            currentLatitude += increment
            if currentLatitude >= self.endLatitude {
                timer.invalidate()
            }
            self.mapview.camera.centerCoordinate.latitude = currentLatitude
        }

    }

    override func viewDidLoad() {
        super.viewDidLoad()
        startMapView()
    }
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.