New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix the route line layer position issue after rerouting. #4062
Conversation
@@ -445,7 +445,7 @@ extension NavigationMapView { | |||
func routeLineRestrictionsGradient(_ restrictionFeatures: [Turf.Feature]) -> [Double: UIColor] { | |||
// If there's no restricted feature, hide the restricted route line layer. | |||
guard restrictionFeatures.count > 0 else { | |||
let gradientStops: [Double: UIColor] = [0.0: traversedRouteColor] | |||
let gradientStops: [Double: UIColor] = [0.0: .defaultTraversedRouteColor] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid the color customization, to hide the whole restricted area layer if it's empty.
@@ -1792,6 +1793,7 @@ open class NavigationMapView: UIView { | |||
// find the topmost non symbol layer for layerIdentifier in lowermostSymbolLayers. | |||
if targetLayer == nil, | |||
layerInfo.type.rawValue != "symbol", | |||
!layerInfo.id.contains("copy"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some style has copy
layer along with other layers at the same strata. It will lead to the wrong topmost non symbol layer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style layer IDs can be arbitrarily named by the style designer. The presence of “copy” means nothing in particular, just that someone clicked Duplicate Layer in Mapbox Studio at some point, so we shouldn’t hard-code this magic value.
Is there anything else we can look for to determine whether a non-symbol layer should be treated like a symbol layer for this purpose? The closest thing I can think of would be to special-case a circle
layer whose circlePitchAlignment
is viewport
, which tends to make the circle look like a symbol. A common use of circle layers is to render things like culs-de-sac at realistic sizes, but those would have a circlePitchAlignment
of map
.
Otherwise, if these extra heuristics don’t work reliably enough, the application should specify a custom layer position.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the suggestion, the copy
is replaced with a general label
in case of this situation would happen. And also the custom layer position for the route line is supported during active navigation and when route line related properties change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The navigation SDK shouldn’t impose any requirements on the layer ID. The layer ID is intended to be freeform text. If a team’s iOS developer is merely integrating a style that a designer authored in Mapbox Studio, we have no opportunity to communicate to the style designer that this exceptional layer should have label
in the ID. On the other hand, if the iOS developer is adding the layer using runtime styling, they might still want to call it something that doesn’t mention “label”.
Do we know more about the use cases where a circle layer would imitate a symbol layer? Can we rely on circlePitchAlignment
to be viewport
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed the id
check. But I don't think the circle layer is the only copy
layer. The check around the viewport
is not definition. When testing the test app, if the styles are not fully loaded, there may be random copy
layers.
In Nav SDK, on both mobile and CarPlay, we have listeners for MapView.mapboxMap.onNext(event: .styleLoaded, handler:)
, when the style changes, The route line layers are updated and regenerated.
If the style is not fully loaded, there may be some random copy
layers, or the right layer position has been found but we couldn't add it.
So the best way to solve this issue, is that the users provide their own customLayerPosition
for the route line. This PR would remember the custom layer position for route line in both mobile and CarPlay. When the style changes, the route line would use the previous remembered custom layer position for the new style by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I opened #4079 to track enhancing the default positioning heuristic to account for circle layers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I adopted #4079 to check the circle
layer as a label layer. Route line will be placed below them as default.
@@ -1792,6 +1793,7 @@ open class NavigationMapView: UIView { | |||
// find the topmost non symbol layer for layerIdentifier in lowermostSymbolLayers. | |||
if targetLayer == nil, | |||
layerInfo.type.rawValue != "symbol", | |||
!layerInfo.id.contains("copy"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style layer IDs can be arbitrarily named by the style designer. The presence of “copy” means nothing in particular, just that someone clicked Duplicate Layer in Mapbox Studio at some point, so we shouldn’t hard-code this magic value.
Is there anything else we can look for to determine whether a non-symbol layer should be treated like a symbol layer for this purpose? The closest thing I can think of would be to special-case a circle
layer whose circlePitchAlignment
is viewport
, which tends to make the circle look like a symbol. A common use of circle layers is to render things like culs-de-sac at realistic sizes, but those would have a circlePitchAlignment
of map
.
Otherwise, if these extra heuristics don’t work reliably enough, the application should specify a custom layer position.
a1bf830
to
4c65531
Compare
/** | ||
A custom route line layer position. | ||
*/ | ||
var customRouteLineLayerPosition: MapboxMaps.LayerPosition? = nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
customRouteLineLayerPosition
is used to remember the custom layer position for route line during active navigation or when route line related properties change.
0428607
to
ca737c5
Compare
Breaking Changes in MapboxCoreNavigationBreaking API Changes
|
2 similar comments
Breaking Changes in MapboxCoreNavigationBreaking API Changes
|
Breaking Changes in MapboxCoreNavigationBreaking API Changes
|
…t nonsymbol layer.
2d89b9d
to
6f9d2dc
Compare
@@ -1794,6 +1803,11 @@ open class NavigationMapView: UIView { | |||
layerInfo.type.rawValue != "symbol", | |||
let sourceLayer = mapView.mapboxMap.style.layerProperty(for: layerInfo.id, property: "source-layer").value as? String, | |||
!sourceLayer.isEmpty { | |||
if layerInfo.type.rawValue == "circle", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to #4079 , add check for circle
type label layer, route line will be placed below them.
@@ -1794,6 +1803,11 @@ open class NavigationMapView: UIView { | |||
layerInfo.type.rawValue != "symbol", | |||
let sourceLayer = mapView.mapboxMap.style.layerProperty(for: layerInfo.id, property: "source-layer").value as? String, | |||
!sourceLayer.isEmpty { | |||
if layerInfo.type.rawValue == "circle", | |||
let isPersistentCircle = try? mapView.mapboxMap.style.isPersistentLayer(id: layerInfo.id), | |||
!isPersistentCircle { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this logic correct? I would’ve assumed that any kind of annotation or data visualization atop the map would use a persistent circle layer, so a persistent circle layer would need to be skipped, but a non-persistent circle layer would be treated as the target layer.
@@ -1794,6 +1803,11 @@ open class NavigationMapView: UIView { | |||
layerInfo.type.rawValue != "symbol", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nesting the if
statement below gets confusing. I think this would more clearly communicate the intention:
(layerInfo.type.rawValue != "symbol" and !(layerInfo.type.rawValue == "circle" and mapView.mapboxMap.style.isPersistentLayer(id: layerInfo.id)))
Description
This Pr is to fix the issue of route line layer position issue after rerouting.
Implementation
label
layer . During style loading, somelabel
layers exist above symbol layers, such aspoi label copy
as acircle layer
but above the symbol layer ofpoi label
. So it will cause theNavigationMapView.layerPosition(for:route:customLayerPosition:)
found the wrong topmost non-symbol layer, especially for route line.Use cases
Call
NavigationMapView.show(_:layerPosition:legIndex:)
to provide custom layer position for route line in both CarPlay and mobile.During active navigation, when alternative routes update, call
NavigationMapView.show(continuousAlternatives:)
. Whenreroute
,refresh
,routeProgress
update, callNavigationMapView.updateRouteLine(routeProgress:coordinate:shouldRedraw:)
. They will keep the custom layer position for route line in both mobile and CarPlay.Screenshots or Gifs