Add markers using a Symbol layer
This example demonstrates adding markers to a Mapbox map using a Symbol layer.
A symbol layer renders icons and text at points or along lines on a map. Compared to regular annotations, it provides more customization but it is also more complex to use. Point annotations are a simpler way to create annotations that use a symbol layer under the hood.
In this example, two different marker images are added to the map, each associated
with specific marker properties. Symbol markers are then created at specified coordinates
with the corresponding properties. The markers' styling, including image expressions,
anchor points, rotation, overlapping behavior, and offsets, is configured using SymbolLayer
.
The example provides a guide on how to add custom symbol markers with different properties
and styling options to a Mapbox map on iOS.
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()
let centerCoordinate = CLLocationCoordinate2D(latitude: 55.70651, longitude: 12.554729)
let options = MapInitOptions(cameraOptions: CameraOptions(center: centerCoordinate, zoom: 8))
mapView = MapView(frame: view.bounds, mapInitOptions: options)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(mapView)
mapView.mapboxMap.onMapLoaded.observeNext { [weak self] _ in
guard let self = self else { return }
self.prepareStyle()
}.store(in: &cancelables)
mapView.mapboxMap.styleURI = .streets
}
// MARK: - Style management
private func prepareStyle() {
try? mapView.mapboxMap.addImage(UIImage(named: "intermediate-pin")!, id: Constants.BLUE_ICON_ID)
try? mapView.mapboxMap.addImage(UIImage(named: "dest-pin")!, id: Constants.RED_ICON_ID)
var features = [Feature]()
var feature = Feature(geometry: Point(LocationCoordinate2D(latitude: 55.608166, longitude: 12.65147)))
feature.properties = [Constants.ICON_KEY: .string(Constants.BLUE_MARKER_PROPERTY)]
features.append(feature)
var feature1 = Feature(geometry: Point(LocationCoordinate2D(latitude: 55.70651, longitude: 12.554729)))
feature1.properties = [Constants.ICON_KEY: .string(Constants.RED_MARKER_PROPERTY)]
features.append(feature1)
var source = GeoJSONSource(id: Constants.SOURCE_ID)
source.data = .featureCollection(FeatureCollection(features: features))
try? mapView.mapboxMap.addSource(source)
let rotateExpression = Exp(.match) {
Exp(.get) { Constants.ICON_KEY }
Constants.BLUE_MARKER_PROPERTY
45
0
}
let imageExpression = Exp(.match) {
Exp(.get) { Constants.ICON_KEY }
Constants.BLUE_MARKER_PROPERTY
Constants.BLUE_ICON_ID
Constants.RED_MARKER_PROPERTY
Constants.RED_ICON_ID
Constants.RED_ICON_ID
}
var layer = SymbolLayer(id: Constants.LAYER_ID, source: Constants.SOURCE_ID)
layer.iconImage = .expression(imageExpression)
layer.iconAnchor = .constant(.bottom)
layer.iconAllowOverlap = .constant(false)
layer.iconRotate = .expression(rotateExpression)
// Add Y-offset so icon will point to exact location.
layer.iconOffset = .constant([0, 12])
try? mapView.mapboxMap.addLayer(layer)
}
}
extension ViewController {
private enum Constants {
static let ICON_KEY = "icon_key"
static let BLUE_MARKER_PROPERTY = "icon_blue_property"
static let RED_MARKER_PROPERTY = "icon_red_property"
static let BLUE_ICON_ID = "blue"
static let RED_ICON_ID = "red"
static let SOURCE_ID = "source_id"
static let LAYER_ID = "layer_id"
}
}