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.
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.
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"
}
}