Skip to content

Commit 2ec8e9c

Browse files
authored
Add traversed route line layer to customize traversedRouteColor (#4106)
1 parent 71b568a commit 2ec8e9c

File tree

5 files changed

+75
-10
lines changed

5 files changed

+75
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
* Fixed an issue where the map would cut off a continuous alternative route to appear as if it began after the deviation point. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085))
2323
* Fixed an issue where the callout annotating a continuous alternative route appeared far away from the route and contained an inaccurate travel time. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085))
2424
* Fixed an issue where some roads were shown as restricted on the route line even if public access is allowed for “local traffic only”. ([#4085](https://github.com/mapbox/mapbox-navigation-ios/pull/4085))
25+
* Fixed an issue where the `NavigationMapView.traversedRouteColor` property had no effect on the traversed part of the route line. ([#4106](https://github.com/mapbox/mapbox-navigation-ios/pull/4106))
2526

2627
### Guidance Instructions
2728

Sources/MapboxNavigation/NavigationMapView.swift

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,10 @@ open class NavigationMapView: UIView {
297297
parentLayerIdentifier = addRouteCasingLayer(route,
298298
below: parentLayerIdentifier,
299299
isMainRoute: index == 0)
300+
301+
if index == 0 && routeLineTracksTraversal {
302+
parentLayerIdentifier = addTraversedRouteLayer(route, below: parentLayerIdentifier)
303+
}
300304
}
301305

302306
continuousAlternatives?.forEach { routeAlternative in
@@ -336,6 +340,7 @@ open class NavigationMapView: UIView {
336340
sourceIdentifiers.insert($0.element.identifier(.restrictedRouteAreaSource))
337341
layerIdentifiers.insert($0.element.identifier(.route(isMainRoute: $0.offset == 0)))
338342
layerIdentifiers.insert($0.element.identifier(.routeCasing(isMainRoute: $0.offset == 0)))
343+
layerIdentifiers.insert($0.element.identifier(.traversedRoute))
339344
layerIdentifiers.insert($0.element.identifier(.restrictedRouteAreaRoute))
340345
}
341346

@@ -362,14 +367,6 @@ open class NavigationMapView: UIView {
362367
mapView.mapboxMap.style.removeSources(sourceIdentifiers)
363368
}
364369

365-
func removeRestrictedRouteArea() {
366-
guard let sourceIdentifier = routes?.first?.identifier(.restrictedRouteAreaSource),
367-
let layerIdentifier = routes?.first?.identifier(.restrictedRouteAreaRoute) else { return }
368-
369-
mapView.mapboxMap.style.removeLayers(Set([layerIdentifier]))
370-
mapView.mapboxMap.style.removeSources(Set([sourceIdentifier]))
371-
}
372-
373370
/**
374371
Shows the step arrow given the current `RouteProgress`.
375372

@@ -625,7 +622,7 @@ open class NavigationMapView: UIView {
625622
let shape = delegate?.navigationMapView(self, shapeFor: route) ?? defaultShape
626623

627624
let geoJSONSource = self.geoJSONSource(shape)
628-
let sourceIdentifier = route.identifier(.source(isMainRoute: isMainRoute, isSourceCasing: true))
625+
let sourceIdentifier = route.identifier(.source(isMainRoute: isMainRoute, isSourceCasing: false))
629626

630627
do {
631628
if mapView.mapboxMap.style.sourceExists(withId: sourceIdentifier) {
@@ -719,7 +716,7 @@ open class NavigationMapView: UIView {
719716
let shape = delegate?.navigationMapView(self, casingShapeFor: route) ?? defaultShape
720717

721718
let geoJSONSource = self.geoJSONSource(shape)
722-
let sourceIdentifier = route.identifier(.source(isMainRoute: isMainRoute, isSourceCasing: isMainRoute))
719+
let sourceIdentifier = route.identifier(.source(isMainRoute: isMainRoute, isSourceCasing: true))
723720

724721
do {
725722
if mapView.mapboxMap.style.sourceExists(withId: sourceIdentifier) {
@@ -787,6 +784,65 @@ open class NavigationMapView: UIView {
787784
return layerIdentifier
788785
}
789786

787+
@discardableResult func addTraversedRouteLayer(_ route: Route, below parentLayerIndentifier: String? = nil) -> String? {
788+
guard let defaultShape = route.shape else { return nil }
789+
790+
// The traversed route layer should have the source as the main route casing source.
791+
let sourceIdentifier = route.identifier(.source(isMainRoute: true, isSourceCasing: true))
792+
793+
if !mapView.mapboxMap.style.sourceExists(withId: sourceIdentifier) {
794+
let shape = delegate?.navigationMapView(self, casingShapeFor: route) ?? defaultShape
795+
let geoJSONSource = self.geoJSONSource(shape)
796+
do {
797+
try mapView.mapboxMap.style.addSource(geoJSONSource, id: sourceIdentifier)
798+
} catch {
799+
Log.error("Failed to add route casing source \(sourceIdentifier) for traversed route with error: \(error.localizedDescription).",
800+
category: .navigationUI)
801+
}
802+
}
803+
804+
var lineLayer: LineLayer? = nil
805+
let layerIdentifier = route.identifier(.traversedRoute)
806+
807+
let layerAlreadyExists = mapView.mapboxMap.style.layerExists(withId: layerIdentifier)
808+
if layerAlreadyExists {
809+
lineLayer = try? mapView.mapboxMap.style.layer(withId: layerIdentifier) as? LineLayer
810+
}
811+
812+
if lineLayer == nil {
813+
lineLayer = LineLayer(id: layerIdentifier)
814+
lineLayer?.source = sourceIdentifier
815+
lineLayer?.lineColor = .constant(.init(traversedRouteColor))
816+
// The traversed route layer should have the same width as the main route casing layer.
817+
lineLayer?.lineWidth = .expression(Expression.routeLineWidthExpression(1.5))
818+
lineLayer?.lineJoin = .constant(.round)
819+
lineLayer?.lineCap = .constant(.round)
820+
}
821+
822+
if let lineLayer = lineLayer {
823+
do {
824+
var layerPosition: MapboxMaps.LayerPosition? = nil
825+
if let parentLayerIndentifier = parentLayerIndentifier, mapView.mapboxMap.style.layerExists(withId: parentLayerIndentifier) {
826+
layerPosition = .below(parentLayerIndentifier)
827+
} else {
828+
layerPosition = self.layerPosition(for: layerIdentifier, route: route)
829+
}
830+
if layerAlreadyExists {
831+
if let layerPosition = layerPosition {
832+
try mapView.mapboxMap.style.moveLayer(withId: layerIdentifier, to: layerPosition)
833+
}
834+
} else {
835+
try mapView.mapboxMap.style.addPersistentLayer(lineLayer, layerPosition: layerPosition)
836+
}
837+
} catch {
838+
Log.error("Failed to add traversed route layer \(layerIdentifier) with error: \(error.localizedDescription).",
839+
category: .navigationUI)
840+
}
841+
}
842+
843+
return layerIdentifier
844+
}
845+
790846
func geoJSONSource(_ shape: LineString) -> GeoJSONSource {
791847
var geoJSONSource = GeoJSONSource()
792848
geoJSONSource.data = .geometry(.lineString(shape))
@@ -1750,6 +1806,7 @@ open class NavigationMapView: UIView {
17501806
LayerIdentifier.buildingExtrusionLayer,
17511807
route?.identifier(.routeCasing(isMainRoute: false)),
17521808
route?.identifier(.route(isMainRoute: false)),
1809+
route?.identifier(.traversedRoute),
17531810
route?.identifier(.routeCasing(isMainRoute: true)),
17541811
route?.identifier(.route(isMainRoute: true)),
17551812
route?.identifier(.restrictedRouteAreaRoute)

Sources/MapboxNavigation/Route.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ extension Route {
142142
return "\(identifier).\(isMainRoute ? "main" : "alternative").route_line"
143143
case .routeCasing(isMainRoute: let isMainRoute):
144144
return "\(identifier).\(isMainRoute ? "main" : "alternative").route_line_casing"
145+
case .traversedRoute:
146+
return "\(identifier).traversed_route"
145147
case .restrictedRouteAreaSource:
146148
return "\(identifier).restricted_area_source"
147149
case .restrictedRouteAreaRoute:

Sources/MapboxNavigation/RouteLineType.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ enum RouteLineType {
88

99
case routeCasing(isMainRoute: Bool)
1010

11+
case traversedRoute
12+
1113
case restrictedRouteAreaSource
1214

1315
case restrictedRouteAreaRoute

Tests/MapboxNavigationTests/RouteLineLayerPositionTests.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,11 @@ class RouteLineLayerPositionTests: TestCase {
238238
navigationMapView.show([multilegRoute], layerPosition: customRouteLineLayerPosition)
239239
navigationMapView.removeWaypoints()
240240
navigationMapView.showsRestrictedAreasOnRoute = false
241+
navigationMapView.routeLineTracksTraversal = true
241242

242243
expectedLayerSequence = [
243244
buildingLayer["id"]!,
245+
multilegRoute.identifier(.traversedRoute),
244246
multilegRoute.identifier(.routeCasing(isMainRoute: true)),
245247
multilegRoute.identifier(.route(isMainRoute: true)),
246248
roadTrafficLayer["id"]!,
@@ -296,6 +298,7 @@ class RouteLineLayerPositionTests: TestCase {
296298
navigationMapView.showWaypoints(on: multilegRoute)
297299
navigationMapView.show([multilegRoute])
298300
navigationMapView.showsRestrictedAreasOnRoute = true
301+
navigationMapView.routeLineTracksTraversal = false
299302

300303
expectedLayerSequence = [
301304
buildingLayer["id"]!,

0 commit comments

Comments
 (0)