# Animate a line

> **Note (legacy): A newer version of the Maps SDK is available**
> 
> This page uses v6.4.1 of the Mapbox Maps SDK. A newer version of the SDK is available. Learn about the latest version, v11.29.0, in the [Maps SDK documentation](https://docs.mapbox.com/ios/maps/guides/).

Your browser doesn't support HTML5 video. Open [link to the video](https://docs.mapbox.com/ios/ios/assets/medias/AnimatedLineExample-e5f1198fd221bc4e472745739591c00a.mp4).

Related examples: [dynamically-styled line](https://docs.mapbox.com/ios/legacy/maps/examples/runtime-add-line/).

**Swift**

Title: `ViewController`

[View on GitHub](https://github.com/mapbox/ios-sdk-examples/tree/298e050be7352eb28cee6f03e02945593140c1f3/Examples/Swift/AnimatedLineExample.swift)

```swift
import Mapbox

class ViewController: UIViewController, MGLMapViewDelegate {
    var mapView: MGLMapView!
    var timer: Timer?
    var polylineSource: MGLShapeSource?
    var currentIndex = 1
    var allCoordinates: [CLLocationCoordinate2D]!

    override func viewDidLoad() {
        super.viewDidLoad()

        mapView = MGLMapView(frame: view.bounds)
        mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

        mapView.setCenter(
            CLLocationCoordinate2D(latitude: 45.5076, longitude: -122.6736),
            zoomLevel: 11,
            animated: false)
        view.addSubview(mapView)

        mapView.delegate = self

        allCoordinates = coordinates
    }

    // Wait until the map is loaded before adding to the map.
    func mapViewDidFinishLoadingMap(_ mapView: MGLMapView) {
        addPolyline(to: mapView.style!)
        animatePolyline()
    }

    func addPolyline(to style: MGLStyle) {
        // Add an empty MGLShapeSource, we’ll keep a reference to this and add points to this later.
        let source = MGLShapeSource(identifier: "polyline", shape: nil, options: nil)
        style.addSource(source)
        polylineSource = source

        // Add a layer to style our polyline.
        let layer = MGLLineStyleLayer(identifier: "polyline", source: source)
        layer.lineJoin = NSExpression(forConstantValue: "round")
        layer.lineCap = NSExpression(forConstantValue: "round")
        layer.lineColor = NSExpression(forConstantValue: UIColor.red)

        // The line width should gradually increase based on the zoom level.
        layer.lineWidth = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)",
                                       [14: 5, 18: 20])
        style.addLayer(layer)
    }

    func animatePolyline() {
        currentIndex = 1

        // Start a timer that will simulate adding points to our polyline. This could also represent coordinates being added to our polyline from another source, such as a CLLocationManagerDelegate.
        timer = Timer.scheduledTimer(timeInterval: 0.05, target: self, selector: #selector(tick), userInfo: nil, repeats: true)
    }

    @objc func tick() {
        if currentIndex > allCoordinates.count {
            timer?.invalidate()
            timer = nil
            return
        }

        // Create a subarray of locations up to the current index.
        let coordinates = Array(allCoordinates[0..<currentIndex])

        // Update our MGLShapeSource with the current locations.
        updatePolylineWithCoordinates(coordinates: coordinates)

        currentIndex += 1
    }

    func updatePolylineWithCoordinates(coordinates: [CLLocationCoordinate2D]) {
        var mutableCoordinates = coordinates

        let polyline = MGLPolylineFeature(coordinates: &mutableCoordinates, count: UInt(mutableCoordinates.count))

        // Updating the MGLShapeSource’s shape will have the map redraw our polyline with the current coordinates.
        polylineSource?.shape = polyline
    }

    let coordinates = [
        (-122.63748, 45.52214),
        (-122.64855, 45.52218),
        (-122.6545, 45.52219),
        (-122.65497, 45.52196),
        (-122.65631, 45.52104),
        (-122.6578, 45.51935),
        (-122.65867, 45.51848),
        (-122.65872, 45.51293),
        (-122.66576, 45.51295),
        (-122.66745, 45.51252),
        (-122.66813, 45.51244),
        (-122.67359, 45.51385),
        (-122.67415, 45.51406),
        (-122.67481, 45.51484),
        (-122.676, 45.51532),
        (-122.68106, 45.51668),
        (-122.68503, 45.50934),
        (-122.68546, 45.50858),
        (-122.6852, 45.50783),
        (-122.68424, 45.50714),
        (-122.68433, 45.50585),
        (-122.68429, 45.50521),
        (-122.68456, 45.50445),
        (-122.68538, 45.50371),
        (-122.68653, 45.50311),
        (-122.68731, 45.50292),
        (-122.68742, 45.50253),
        (-122.6867, 45.50239),
        (-122.68545, 45.5026),
        (-122.68407, 45.50294),
        (-122.68357, 45.50271),
        (-122.68236, 45.50055),
        (-122.68233, 45.49994),
        (-122.68267, 45.49955),
        (-122.68257, 45.49919),
        (-122.68376, 45.49842),
        (-122.68428, 45.49821),
        (-122.68573, 45.49798),
        (-122.68923, 45.49805),
        (-122.68926, 45.49857),
        (-122.68814, 45.49911),
        (-122.68865, 45.49921),
        (-122.6897, 45.49905),
        (-122.69346, 45.49917),
        (-122.69404, 45.49902),
        (-122.69438, 45.49796),
        (-122.69504, 45.49697),
        (-122.69624, 45.49661),
        (-122.69781, 45.4955),
        (-122.69803, 45.49517),
        (-122.69711, 45.49508),
        (-122.69688, 45.4948),
        (-122.69744, 45.49368),
        (-122.69702, 45.49311),
        (-122.69665, 45.49294),
        (-122.69788, 45.49212),
        (-122.69771, 45.49264),
        (-122.69835, 45.49332),
        (-122.7007, 45.49334),
        (-122.70167, 45.49358),
        (-122.70215, 45.49401),
        (-122.70229, 45.49439),
        (-122.70185, 45.49566),
        (-122.70215, 45.49635),
        (-122.70346, 45.49674),
        (-122.70517, 45.49758),
        (-122.70614, 45.49736),
        (-122.70663, 45.49736),
        (-122.70807, 45.49767),
        (-122.70807, 45.49798),
        (-122.70717, 45.49798),
        (-122.70713, 45.4984),
        (-122.70774, 45.49893)
        ].map({CLLocationCoordinate2D(latitude: $0.1, longitude: $0.0)})
}
```

**Objective C**

Title: `ViewController`

[View on GitHub](https://github.com/mapbox/ios-sdk-examples/tree/298e050be7352eb28cee6f03e02945593140c1f3/Examples/ObjectiveC/AnimatedLineExample.m)

```swift
#import "ViewController.h"
@import Mapbox;
@interface ViewController () <MGLMapViewDelegate>

@property (nonatomic) MGLMapView *mapView;
@property (nonatomic) MGLShapeSource *polylineSource;
@property (nonatomic) NSArray<CLLocation *> *locations;
@property (nonatomic) NSInteger currentIndex;
@property (nonatomic, strong) NSTimer *timer;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds];
    self.mapView.delegate = self;

    self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

    [self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(45.5076, -122.6736)
                            zoomLevel:11
                             animated:NO];

    [self.view addSubview:self.mapView];

}

// Wait until the map is loaded before adding to the map.
- (void)mapViewDidFinishLoadingMap:(MGLMapView *)mapView {
    [self addPolylineToStyle:mapView.style];
    [self animatePolyline];
}

- (void)addPolylineToStyle:(MGLStyle *)style {
    // Add an empty MGLShapeSource, we’ll keep a reference to this and add points to this later.
    MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"polyline" features:@[] options:nil];
    [style addSource:source];
    self.polylineSource = source;
    
    // Add a layer to style our polyline.
    MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"polyline" source:source];
    layer.lineJoin = [NSExpression expressionForConstantValue:@"round"];
    layer.lineCap = layer.lineJoin = [NSExpression expressionForConstantValue:@"round"];
    layer.lineColor = [NSExpression expressionForConstantValue:[UIColor redColor]];
    
    // The line width should gradually increase based on the zoom level.
    layer.lineWidth = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)",
                       @{@14: @5, @18: @20}];
    [self.mapView.style addLayer:layer];
}

- (void)animatePolyline {
    self.currentIndex = 1;

    // Start a timer that will simulate adding points to our polyline. This could also represent coordinates being added to our polyline from another source, such as a CLLocationManagerDelegate.
    self.timer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(tick:) userInfo:nil repeats:YES];
}

- (void)tick:(NSTimer*)timer {
    if (self.currentIndex > self.locations.count) {
        [self.timer invalidate];
        return;
    }

    // Create a subarray of locations up to the current index.
    NSArray *currentLocations = [self.locations subarrayWithRange:NSMakeRange(0, _currentIndex)];

    // Update our MGLShapeSource with the current locations.
    [self updatePolylineWithLocations:currentLocations];

    self.currentIndex++;
}

- (void)updatePolylineWithLocations:(NSArray<CLLocation *> *)locations {
    CLLocationCoordinate2D coordinates[locations.count];

    for (NSUInteger i = 0; i < locations.count; i++) {
        coordinates[i] = locations[i].coordinate;
    }

    MGLPolylineFeature *polyline = [MGLPolylineFeature polylineWithCoordinates:coordinates count:locations.count];

    // Updating the MGLShapeSource’s shape will have the map redraw our polyline with the current coordinates.
    self.polylineSource.shape = polyline;
}

- (NSArray<CLLocation *> *)locations {
    NSArray *coordinates = @[
        @[@(-122.63748), @45.52214],
        @[@(-122.64855), @45.52218],
        @[@(-122.6545), @45.52219],
        @[@(-122.65497), @45.52196],
        @[@(-122.65631), @45.52104],
        @[@(-122.6578), @45.51935],
        @[@(-122.65867), @45.51848],
        @[@(-122.65872), @45.51293],
        @[@(-122.66576), @45.51295],
        @[@(-122.66745), @45.51252],
        @[@(-122.66813), @45.51244],
        @[@(-122.67359), @45.51385],
        @[@(-122.67415), @45.51406],
        @[@(-122.67481), @45.51484],
        @[@(-122.676), @45.51532],
        @[@(-122.68106), @45.51668],
        @[@(-122.68503), @45.50934],
        @[@(-122.68546), @45.50858],
        @[@(-122.6852), @45.50783],
        @[@(-122.68424), @45.50714],
        @[@(-122.68433), @45.50585],
        @[@(-122.68429), @45.50521],
        @[@(-122.68456), @45.50445],
        @[@(-122.68538), @45.50371],
        @[@(-122.68653), @45.50311],
        @[@(-122.68731), @45.50292],
        @[@(-122.68742), @45.50253],
        @[@(-122.6867), @45.50239],
        @[@(-122.68545), @45.5026],
        @[@(-122.68407), @45.50294],
        @[@(-122.68357), @45.50271],
        @[@(-122.68236), @45.50055],
        @[@(-122.68233), @45.49994],
        @[@(-122.68267), @45.49955],
        @[@(-122.68257), @45.49919],
        @[@(-122.68376), @45.49842],
        @[@(-122.68428), @45.49821],
        @[@(-122.68573), @45.49798],
        @[@(-122.68923), @45.49805],
        @[@(-122.68926), @45.49857],
        @[@(-122.68814), @45.49911],
        @[@(-122.68865), @45.49921],
        @[@(-122.6897), @45.49905],
        @[@(-122.69346), @45.49917],
        @[@(-122.69404), @45.49902],
        @[@(-122.69438), @45.49796],
        @[@(-122.69504), @45.49697],
        @[@(-122.69624), @45.49661],
        @[@(-122.69781), @45.4955],
        @[@(-122.69803), @45.49517],
        @[@(-122.69711), @45.49508],
        @[@(-122.69688), @45.4948],
        @[@(-122.69744), @45.49368],
        @[@(-122.69702), @45.49311],
        @[@(-122.69665), @45.49294],
        @[@(-122.69788), @45.49212],
        @[@(-122.69771), @45.49264],
        @[@(-122.69835), @45.49332],
        @[@(-122.7007), @45.49334],
        @[@(-122.70167), @45.49358],
        @[@(-122.70215), @45.49401],
        @[@(-122.70229), @45.49439],
        @[@(-122.70185), @45.49566],
        @[@(-122.70215), @45.49635],
        @[@(-122.70346), @45.49674],
        @[@(-122.70517), @45.49758],
        @[@(-122.70614), @45.49736],
        @[@(-122.70663), @45.49736],
        @[@(-122.70807), @45.49767],
        @[@(-122.70807), @45.49798],
        @[@(-122.70717), @45.49798],
        @[@(-122.70713), @45.4984],
        @[@(-122.70774), @45.49893],
    ];

    NSMutableArray<CLLocation *> *locations = [NSMutableArray array];
    for (NSArray<NSNumber *> *c in coordinates) {
        [locations addObject:[[CLLocation alloc] initWithLatitude:[c[1] doubleValue] longitude:[c[0] doubleValue]]];
    }
    return locations;
}

@end
```