Add a line style layer from GeoJSON
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.9.0, in the Maps SDK documentation.
Related examples: dynamically-styled line and animated line.
import Mapbox
class ViewController: UIViewController, MGLMapViewDelegate {
var mapView: MGLMapView!
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
}
// Wait until the map is loaded before adding to the map.
func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {
loadGeoJson()
}
func loadGeoJson() {
DispatchQueue.global().async {
// Get the path for example.geojson in the app’s bundle.
guard let jsonUrl = Bundle.main.url(forResource: "example", withExtension: "geojson") else {
preconditionFailure("Failed to load local GeoJSON file")
}
guard let jsonData = try? Data(contentsOf: jsonUrl) else {
preconditionFailure("Failed to parse GeoJSON file")
}
DispatchQueue.main.async {
self.drawPolyline(geoJson: jsonData)
}
}
}
func drawPolyline(geoJson: Data) {
// Add our GeoJSON data to the map as an MGLGeoJSONSource.
// We can then reference this data from an MGLStyleLayer.
// MGLMapView.style is optional, so you must guard against it not being set.
guard let style = self.mapView.style else { return }
guard let shapeFromGeoJSON = try? MGLShape(data: geoJson, encoding: String.Encoding.utf8.rawValue) else {
fatalError("Could not generate MGLShape")
}
let source = MGLShapeSource(identifier: "polyline", shape: shapeFromGeoJSON, options: nil)
style.addSource(source)
// Create new layer for the line.
let layer = MGLLineStyleLayer(identifier: "polyline", source: source)
// Set the line join and cap to a rounded end.
layer.lineJoin = NSExpression(forConstantValue: "round")
layer.lineCap = NSExpression(forConstantValue: "round")
// Set the line color to a constant blue color.
layer.lineColor = NSExpression(forConstantValue: UIColor(red: 59/255, green: 178/255, blue: 208/255, alpha: 1))
// Use `NSExpression` to smoothly adjust the line width from 2pt to 20pt between zoom levels 14 and 18. The `interpolationBase` parameter allows the values to interpolate along an exponential curve.
layer.lineWidth = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)",
[14: 2, 18: 20])
// We can also add a second layer that will draw a stroke around the original line.
let casingLayer = MGLLineStyleLayer(identifier: "polyline-case", source: source)
// Copy these attributes from the main line layer.
casingLayer.lineJoin = layer.lineJoin
casingLayer.lineCap = layer.lineCap
// Line gap width represents the space before the outline begins, so should match the main line’s line width exactly.
casingLayer.lineGapWidth = layer.lineWidth
// Stroke color slightly darker than the line color.
casingLayer.lineColor = NSExpression(forConstantValue: UIColor(red: 41/255, green: 145/255, blue: 171/255, alpha: 1))
// Use `NSExpression` to gradually increase the stroke width between zoom levels 14 and 18.
casingLayer.lineWidth = NSExpression(format: "mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", [14: 1, 18: 4])
// Just for fun, let’s add another copy of the line with a dash pattern.
let dashedLayer = MGLLineStyleLayer(identifier: "polyline-dash", source: source)
dashedLayer.lineJoin = layer.lineJoin
dashedLayer.lineCap = layer.lineCap
dashedLayer.lineColor = NSExpression(forConstantValue: UIColor.white)
dashedLayer.lineOpacity = NSExpression(forConstantValue: 0.5)
dashedLayer.lineWidth = layer.lineWidth
// Dash pattern in the format [dash, gap, dash, gap, ...]. You’ll want to adjust these values based on the line cap style.
dashedLayer.lineDashPattern = NSExpression(forConstantValue: [0, 1.5])
style.addLayer(layer)
style.addLayer(dashedLayer)
style.insertLayer(casingLayer, below: layer)
}
}
#import "ViewController.h"
@import Mapbox;
@interface ViewController () <MGLMapViewDelegate>
@property (nonatomic) MGLMapView *mapView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.mapView = [[MGLMapView alloc] initWithFrame:self.view.bounds];
self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(45.5076, -122.6736)
zoomLevel:11
animated:NO];
[self.view addSubview:self.mapView];
self.mapView.delegate = self;
}
// Wait until the map is loaded before adding to the map.
- (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style {
[self loadGeoJSON];
}
- (void)loadGeoJSON {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString *path = [[NSBundle mainBundle] pathForResource:@"example" ofType:@"geojson"];
NSData *jsonData = [NSData dataWithContentsOfFile:path];
dispatch_async(dispatch_get_main_queue(), ^{
[self drawPolyline:jsonData];
});
});
}
- (void)drawPolyline:(NSData *)geoJson {
// Add our GeoJSON data to the map as an MGLShapeSource.
// We can then reference this data from an MGLStyleLayer.
MGLShape *shape = [MGLShape shapeWithData:geoJson encoding:NSUTF8StringEncoding error:nil];
MGLSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"polyline" shape:shape options:nil];
[self.mapView.style addSource:source];
// Create new layer for the line.
MGLLineStyleLayer *layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"polyline" source:source];
// Set the line join and cap to a rounded end.
layer.lineJoin = [NSExpression expressionForConstantValue:[NSValue valueWithMGLLineJoin:MGLLineJoinRound]];
layer.lineCap = [NSExpression expressionForConstantValue:[NSValue valueWithMGLLineCap:MGLLineCapRound]];
// Set the line color to a constant blue color.
layer.lineColor = [NSExpression expressionForConstantValue:[UIColor colorWithRed:59/255.0f green:178/255.0f blue:208/255.0f alpha:1]];
// Use `NSExpression` to smoothly adjust the line width from 2pt to 20pt between zoom levels 14 and 18. The `interpolationBase` parameter allows the values to interpolate along an exponential curve
layer.lineWidth = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)",
@{@14: @2, @18: @20}];
// We can also add a second layer that will draw a stroke around the original line.
MGLLineStyleLayer *casingLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"polyline-case" source:source];
// Copy these attributes from the main line layer.
casingLayer.lineJoin = layer.lineJoin;
casingLayer.lineCap = layer.lineCap;
// Line gap width represents the space before the outline begins, so should match the main line’s line width exactly.
casingLayer.lineGapWidth = layer.lineWidth;
// Stroke color slightly darker than the line color.
casingLayer.lineColor = [NSExpression expressionForConstantValue:[UIColor colorWithRed:41/255.0f green:145/255.0f blue:171/255.0f alpha:1]];
// Use a style function to gradually increase the stroke width between zoom levels 14 and 18.
casingLayer.lineWidth = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)",
@{@14: @1, @18: @4}];
// Just for fun, let’s add another copy of the line with a dash pattern.
MGLLineStyleLayer *dashedLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"polyline-dash" source:source];
dashedLayer.lineJoin = layer.lineJoin;
dashedLayer.lineCap = layer.lineCap;
dashedLayer.lineWidth = layer.lineWidth;
dashedLayer.lineColor = [NSExpression expressionForConstantValue:[UIColor whiteColor]];
dashedLayer.lineOpacity = [NSExpression expressionForConstantValue:@0.5];
// Dash pattern in the format [dash, gap, dash, gap, ...]. You’ll want to adjust these values based on the line cap style.
dashedLayer.lineDashPattern = [NSExpression expressionForConstantValue:@[@0, @1.5]];
[self.mapView.style addLayer:layer];
[self.mapView.style addLayer:dashedLayer];
[self.mapView.style insertLayer:casingLayer belowLayer:layer];
}
@end