Skip to main content

Draw multiple geometries

This example demonstrates how to display multiple geometries on a map using the Mapbox Maps SDK for iOS. The MultipleGeometriesExample class sets up a MapView with a specified center coordinate and zoom level. Next, it loads a string of GeoJSON data, decodes it into a FeatureCollection, and uses addSource to add a data source to the map.

Next, it uses three differentaddLayer methods to add three different layers to the map. The first layer is a CircleLayer that displays a circle at each Point feature in the FeatureCollection. The second is a LineLayer to visualize the LineString features. The third layer is a FillLayer representing the Polygon features.

filter expressions are used to limit the features displayed in each layer based on the geometry type of the feature.

iOS Examples App Available

This example code is part of the Maps SDK for iOS Examples App, a working iOS project available on Github. iOS developers are encouraged to run the examples app locally to interact with this example in an emulator and explore other features of the Maps SDK.

See our Run the Maps SDK for iOS Examples App tutorial for step-by-step instructions.

MultipleGeometriesExample.swift
import UIKit
import MapboxMaps

final class ViewController: UIViewController {
private var mapView: MapView!
private var cancelables = Set<AnyCancelable>()

override func viewDidLoad() {
super.viewDidLoad()

// Set the center coordinate and zoom level.
let centerCoordinate = CLLocationCoordinate2D(latitude: 38.93490939383946, longitude: -77.03619251024163)
let options = MapInitOptions(cameraOptions: CameraOptions(center: centerCoordinate, zoom: 11))

mapView = MapView(frame: view.bounds, mapInitOptions: options)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(mapView)

// Allow the view controller to receive information about map events.
mapView.mapboxMap.onMapLoaded.observeNext { [weak self] _ in
guard let self = self else { return }
self.addGeoJSONSource()
self.addPolygonLayer()
self.addLineStringLayer()
self.addPointLayer()



}.store(in: &cancelables)
}

// Load GeoJSON file from local bundle and decode into a `FeatureCollection`.
private func decodeGeoJSON(from fileName: String) throws -> FeatureCollection? {
guard let path = Bundle.main.path(forResource: fileName, ofType: "geojson") else {
preconditionFailure("File '\(fileName)' not found.")
}

let filePath = URL(fileURLWithPath: path)

var featureCollection: FeatureCollection?

do {
let data = try Data(contentsOf: filePath)
featureCollection = try JSONDecoder().decode(FeatureCollection.self, from: data)
} catch {
print("Error parsing data: \(error)")
}

return featureCollection
}

private func addGeoJSONSource() {
// Attempt to decode GeoJSON from file bundled with application.
guard let featureCollection = try? decodeGeoJSON(from: "GeoJSONSourceExample") else { return }

// Create a GeoJSON data source.
var geoJSONSource = GeoJSONSource(id: Constants.geoJSONDataSourceIdentifier)
geoJSONSource.data = .featureCollection(featureCollection)
try! mapView.mapboxMap.addSource(geoJSONSource)
}

/// Create and style a FillLayer that uses the Polygon Feature's coordinates in the GeoJSON data
private func addPolygonLayer() {
var polygonLayer = FillLayer(id: "fill-layer", source: Constants.geoJSONDataSourceIdentifier)
polygonLayer.filter = Exp(.eq) {
"$type"
"Polygon"
}
polygonLayer.fillColor = .constant(StyleColor(red: 68, green: 105, blue: 247, alpha: 1)!)
polygonLayer.fillOpacity = .constant(0.3)
try! mapView.mapboxMap.addLayer(polygonLayer)
}

private func addLineStringLayer() {
// Create and style a LineLayer that uses the Line String Feature's coordinates in the GeoJSON data
var lineLayer = LineLayer(id: "line-layer", source: Constants.geoJSONDataSourceIdentifier)
lineLayer.filter = Exp(.eq) {
"$type"
"LineString"
}
lineLayer.lineColor = .constant(StyleColor(.red))
lineLayer.lineWidth = .constant(2)
try! mapView.mapboxMap.addLayer(lineLayer)
}

private func addPointLayer() {
// Create a circle layer associated with the GeoJSON data source,
// filter it so that only the point data is shown,
// and apply basic styling to it.
var circleLayer = CircleLayer(id: "circle-layer", source: Constants.geoJSONDataSourceIdentifier)
circleLayer.filter = Exp(.eq) {
"$type"
"Point"
}
circleLayer.circleColor = .constant(StyleColor(.red))
circleLayer.circleRadius = .constant(6.0)
circleLayer.circleStrokeWidth = .constant(2.0)
circleLayer.circleStrokeColor = .constant(StyleColor(.black))
try! mapView.mapboxMap.addLayer(circleLayer)
}
}

extension ViewController {
private enum Constants {
static let geoJSONDataSourceIdentifier = "geoJSON-data-source"
}
}
Was this example helpful?