Setting up a weather map

Setting up a weather map

While the AWFWeatherMapViewController class handles all of the setup necessary to get a fully-functional weather map up and running without any work, there may be times when you want more control over your own weather map.

This example includes the various phases of setting up a weather map in much of the same way as AWFWeatherMapViewController. Depending on your own implementation, you may choose to only use parts of this setup.

The primary steps include:

  1. Ensure you've setup the SDK with your Xweather account access keys.
  2. Configure and create your AWFWeatherMap instance and assign its delegate.
  3. If desired, setup the AWFTimelineView (or alternative custom view) which will be used to show animation progress and allow the user to control playback of the animation. You must also set the timeline view's delegate to receive time change events from the view.
  4. Create a toggleAnimation method that will handle starting or stopping the animation based on the animation's current state. Set the timeline view's playback control action to call this method when tapped.
  5. Setup the appropriate AWFTimelineViewDelegate methods to respond to time changes from the timeline view and update the weather map accordingly.
  6. Setup the appropriate AWFWeatherMapDelegate methods to respond to animation state changes from the weather map and update the timeline view accordingly.
class MapViewController: UIViewController {
    var weatherMap: AWFWeatherMap!
    var timelineView: AWFTimelineView!
    override func viewDidLoad() {
        // setup the weather map config
        let config = AWFWeatherMapConfig()
        // make any changes to your configuration before creating the weather map instance...
        // create the weather map instance
        weatherMap = AWFWeatherMap(mapType: .apple, config: config)
        weatherMap.delegate = self
        timelineView = AWFTimelineView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 50.0))
        timelineView.delegate = self
        timelineView.startDate = weatherMap.timeline.fromTime
        timelineView.endDate = weatherMap.timeline.toTime
        timelineView.currentTime = weatherMap.timeline.fromTime
        // layout the map view container
        weatherMap.weatherMapView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([weatherMap.weatherMapView.topAnchor.constraint(equalTo: view.topAnchor),
                                        weatherMap.weatherMapView.leftAnchor.constraint(equalTo: view.leftAnchor),
                                        weatherMap.weatherMapView.rightAnchor.constraint(equalTo: view.rightAnchor),
                                        weatherMap.weatherMapView.bottomAnchor.constraint(equalTo: view.bottomAnchor)])
        // layout the timeline view
        let timelineHeight: CGFloat = 50.0
        timelineView.translatesAutoresizingMaskIntoConstraints = false
        timelineView.preservesSuperviewLayoutMargins = true
        NSLayoutConstraint.activate([timelineView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor, constant: -timelineHeight),
                                        timelineView.leftAnchor.constraint(equalTo: view.leftAnchor),
                                        timelineView.rightAnchor.constraint(equalTo: view.rightAnchor),
                                        timelineView.bottomAnchor.constraint(equalTo: view.bottomAnchor)])
        // add an action handler for the timeline view's playback control
        timelineView.playButton.addTarget(self, action: #selector(toggleAnimation(sender:)), for: .touchUpInside)
        // start the weather map at the current time
        weatherMap.go(toTime: Date())
    // MARK: Control Handlers
    @objc func toggleAnimation(sender: Any) {
        if let btn = sender as? UIButton {
            if weatherMap.isAnimating || weatherMap.isLoadingAnimation {
                btn.isSelected = false
            } else {
                btn.isSelected = true
// Observe change events on the timelineView so the weather map can be updated accordingly, such as when the user pans
// the timeline or taps the "Now" control to go to the current time/date.
extension MapViewController: AWFTimelineViewDelegate {
    func timelineView(_ timelineView: AWFTimelineView!, didPanTo date: Date!) {
        if weatherMap.config.timelineScrubbingEnabled {
            weatherMap.go(toTime: date)
    func timelineView(_ timelineView: AWFTimelineView!, didSelect date: Date!) {
        weatherMap.go(toTime: date)
// Updates to the timelineView are handled by handling several AWFWeatherMapDelegate methods that notify our controller about changes to the weather map's
// timeline, such as start/end date changes and when the map begins or stops animating.
extension MapViewController: AWFWeatherMapDelegate {
    func weatherMap(_ weatherMap: AWFWeatherMap, didUpdateTimelineRangeFrom fromDate: Date, to toDate: Date) {
        timelineView.startDate = fromDate
        timelineView.endDate = toDate
        timelineView.currentTime = weatherMap.timeline.currentTime
    func weatherMapDidStartAnimating(_ weatherMap: AWFWeatherMap) {
        timelineView.playButton.isSelected = true
    func weatherMapDidStopAnimating(_ weatherMap: AWFWeatherMap) {
        timelineView.playButton.isSelected = false
    func weatherMapDidResetAnimation(_ weatherMap: AWFWeatherMap) {
        timelineView.setProgress(0, animated: true)
    func weatherMap(_ weatherMap: AWFWeatherMap, animationDidUpdateTo date: Date) {
        timelineView.currentTime = date
    func weatherMapDidStartLoadingAnimationData(_ weatherMap: AWFWeatherMap) {
        timelineView.playButton.isSelected = true
    func weatherMapDidFinishLoadingAnimationData(_ weatherMap: AWFWeatherMap) {
        timelineView.setProgress(1.0, animated: true)
    func weatherMapDidCancelLoadingAnimationData(_ weatherMap: AWFWeatherMap) {
        timelineView.playButton.isSelected = false
        timelineView.setProgress(0, animated: true)
    func weatherMap(_ weatherMap: AWFWeatherMap, didUpdateAnimationDataLoadingProgress totalLoaded: Int, total: Int) {
        timelineView.setProgress(CGFloat(totalLoaded) / CGFloat(total), animated: true)