Route line
The Navigation SDK allows you to display route lines on a map, which is an integral component used in turn-by-turn navigation applications.
The interfaces described in this guide provide abstractions to prepare the navigation data and visualize it on a Mapbox Map.
Use the route line UI component
The route line UI component consists of two main classes:
- The
MapboxRouteLineApi
has methods for creating and modifying the route line and producing data describing the view related mutations. - The
MapboxRouteLineView
handles consuming the data produced by theMapboxRouteLineApi
and rendering the results on the map.
By default, the route line UI component displays the route as a solid blue line with a darker blue outline.
Instantiate the route line API
Instantiate the MapboxRouteLineApi
and MapboxRouteLineView
classes in your Activity
or Fragment
.
val routeLineApiOptions = MapboxRouteLineApiOptions.Builder().build()
val routeLineApi = MapboxRouteLineApi(routeLineApiOptions)
val routeLineViewOptions = MapboxRouteLineViewOptions.Builder(context).build()
val routeLineView = MapboxRouteLineView(routeLineViewOptions)
Draw a route line by passing a NavigationRoute
instance to the MapboxRouteLineApi
and rendering the result with the MapboxRouteLineView
. Read more about requesting a NavigationRoute
in the Route generation guide.
A recommended way to draw route lines is by registering a RoutesObserver
with MapboxNavigation
:
private val routesObserver = object : RoutesObserver {
override fun onRoutesChanged(result: RoutesUpdatedResult) {
/*
obtain metadata to enhance visualization of alternative routes
and hide parts that overlap with the primary route
*/
val alternativesMetadata = mapboxNavigation.getAlternativeMetadataFor(
result.navigationRoutes
)
routeLineApi.setNavigationRoutes(
result.navigationRoutes,
alternativesMetadata,
) { value ->
routeLineView.renderRouteDrawData(mapStyle, value)
}
}
}
This approach ensures that whenever routes get updated the new information will be reflected on the route lines. This includes change in selected primary route, re-drawing routes after a reroute event, refreshes to update congestion information, or removal of invalid alternatives after the fork is passed.
Be sure to always unregister observers in onStop()
or onDestroy()
.
Also don't forget to cancel any potential in-flight MapboxRouteLineApi
requests and MapboxRouteLineView
background tasks:
override fun onDestroy() {
super.onDestroy()
routeLineApi.cancel()
routeLineView.cancel()
}
Request routes with the right data
When requesting a route using MapboxNavigation
there are some options that are necessary if you want to display traffic congestion on the route line. You can use RouteOptions.builder().applyDefaultNavigationOptions()
, which will use the PROFILE_DRIVING_TRAFFIC
profile and the required annotations.
If you are using custom route options, be sure to use the PROFILE_DRIVING_TRAFFIC
profile and include at least ANNOTATION_CONGESTION_NUMERIC
and ANNOTATION_DISTANCE
in the annotationsList
. If any of these options are absent, there will not be enough data in the directions response to display traffic congestion on the route line.
val routeOptions = RouteOptions.builder()
.profile(DirectionsCriteria.PROFILE_DRIVING_TRAFFIC)
.annotationsList(
listOf(
DirectionsCriteria.ANNOTATION_CONGESTION_NUMERIC,
DirectionsCriteria.ANNOTATION_DISTANCE
)
)
.coordinates(listOf(origin, destination))
.build()
mapboxNavigation.requestRoutes(routeOptions, callback)
To display alternative route lines, include the alternatives(true)
route option.
val routeOptions = RouteOptions.builder()
.alternatives(true)
.coordinates(listOf(origin, destination))
.build()
mapboxNavigation.requestRoutes(routeOptions, callback)
Handle progress along the route
When progress along the route changes, the MapboxRouteLineApi
must be updated with the latest information to correctly render active route leg or already traveled route part.
Register a RouteProgressObserver
with MapboxNavigation
to keep the route line updated.
private val routeProgressObserver = RouteProgressObserver { routeProgress ->
routeLineApi.updateWithRouteProgress(routeProgress) { result ->
routeLineView.renderRouteLineUpdate(mapStyle, result)
}
}
Always be sure to unregister observers in onStop()
or onDestroy()
.
Customize the route line
Differentiate the traveled route part
To visually differentiate the part of the route that has already been traveled from the route ahead, use the route line API's vanishing route line feature. Enabling this feature will make the section of the route line the behind the user's current location transparent by default, or you can configure a custom color.
Enable this feature using the MapboxRouteLineApiOptions
. The color can be configured with RouteLineColorResources.routeLineTraveledColor
.
val routeLineApiOptions = MapboxRouteLineApiOptions.Builder()
.vanishingRouteLineEnabled(true)
.build()
Then, register an OnIndicatorPositionChangedListener
with the map location component to pass information about the current location of the user indicator on the map to the route line. This information is used to calculate the part of the route line that needs to be updated.
mapView.location.addOnIndicatorPositionChangedListener(onPositionChangedListener)
private val onPositionChangedListener = OnIndicatorPositionChangedListener { point ->
val result = routeLineApi.updateTraveledRouteLine(point)
routeLineView.renderRouteLineUpdate(mapStyle, result)
}
Always be sure to unregister observers in onStop()
or onDestroy()
.
MapboxRouteLineApiOptions
but also data from both the OnIndicatorPositionChangedListener
and RouteProgressObserver
(see Handle route updates) needs to be provided.Position the route line relative to map layers
The map on which you are displaying your route line contains many individual layers (for example, roads, buildings, labels, and more). The route line UI component consists of multiple layers that are added to the map.
By default, the route line is placed on top of all the other layers in the map. This rarely the most optimal position for a route line because it may appear on top of road labels and other labels on the map.
You can specify the route line layers' vertical position within all map layers using the routeLineBelowLayerId
parameter of MapboxRouteLineViewOptions
. The route line layers will be placed below the layer with the ID indicated in the routeLineBelowLayerId
option.
val routeLineViewOptions = MapboxRouteLineViewOptions.Builder()
.routeLineBelowLayerId("road-label")
.build()
routeLineBelowLayerId
value of "road-label"
, but this layer is not present in all map styles. If you are using a custom map style or another Mapbox-designed style, you can find the layer IDs that exist in the style by opening the style in Mapbox Studio or printing the style JSON to the console. For more information see Finding layer ids.MIDDLE
slot. Support for selecting the slot to which the route line should be inserted will be introduced in future releases.Change the style of the route line
The MapboxRouteLineViewOptions
class offers several options for customizing the style of the route line.
Color
You can customize the route line colors by providing RouteLineColorResources
to the MapboxRouteLineViewOptions.Builder
class.
val customColorResources = RouteLineColorResources.Builder()
.routeDefaultColor(Color.parseColor("#FFCC00"))
// ... etc
.build()
val routeLineViewOptions = MapboxRouteLineViewOptions.Builder(this)
.routeLineColorResources(customColorResources)
.build()
Scale
A route line consists of multiple layers on the map. The lowest layer is called the casing layer. Above the casing layer is the main route line layer. And the top layer is a traffic line layer. By default, the casing layer has the greatest width giving the appearance of a border around the route line and traffic line.
The scaling behavior of these lines is determined by the Expression
class from the Maps SDK. With the RouteLineResources.Builder
you can customize the scaling expressions rather than using the defaults. See the Maps SDK documentation for more information on creating expressions.
val scaleExpressions = RouteLineScaleExpressions.Builder()
.routeCasingLineScaleExpression(customCasingExpression)
.routeLineScaleExpression(customRouteLineExpression)
.routeTrafficLineScaleExpression(customTrafficLineExpression)
.build()
val routeLineViewOptions = MapboxRouteLineViewOptions.Builder(this)
.scaleExpressions(scaleExpressions)
.build()
Style inactive route legs
It's common to use routes with multiple waypoints. For better route visibility, you may want the route line to visually differentiate between the active route leg and inactive route legs.
When this feature is enabled and properly configured, the inactive route legs will appear a different color (or transparency) than the active route leg, making it clearer to the driver where the route is taking them. As the driver transitions from one route leg to another, the route leg colors will change to differentiate the active route leg from the inactive route legs. This feature only works on routes with multiple waypoints.
Enable this feature by setting the MapboxRouteLineApiOptions.styleInactiveRouteLegsIndependently
option to true
.
val routeLineApiOptions = MapboxRouteLineApiOptions.Builder()
.styleInactiveRouteLegsIndependently(true)
.build()
Set the colors used for inactive route legs using one of the options in the RouteLineColorResources
class. There are multiple options to style inactive route legs. For example, you can use inActiveRouteLegsColor
to set the default color of inactive route legs. Additionally, there are options to style congestion levels, restricted roads, or closures on inactive route legs.
val customColorResources = RouteLineColorResources.Builder()
.inActiveRouteLegsColor(Color.parseColor("#FFCC00"))
.build()
MapboxRouteLineApiOptions
but also data from the RouteProgressObserver
(see Handle route updates) needs to be provided.Display restricted road sections
The MapboxRouteLineViewOptions
class includes an option to display roads or sections of roads designated as restricted. When you set this option to true, the route line will display a dashed line.
val routeLineViewOptions = MapboxRouteLineViewOptions.Builder(context)
.displayRestrictedRoadSections(true)
.build()
Further customization of the restricted road dashed line is available in the MapboxRouteLineViewOptions
class. The available options are restrictedRoadDashArray
, restrictedRoadOpacity
and restrictedRoadLineWidth
. These options are used when creating the layer that contains the restricted line and correspond to the dash line layer options of the Maps SDK. See the Maps SDK line layer documentation for further explanation of these options.
You can configure the color of the dashed line representing restricted roads using the RouteLineColorResources
class to set the restrictedRoadColor
and alternativeRouteRestrictedRoadColor
options.
val customColorResources = RouteLineColorResources.Builder()
.restrictedRoadColor(Color.parseColor("#FFCC00"))
.alternativeRouteRestrictedRoadColor(Color.parseColor("#FFCC00"))
.build()
Display soft gradient for traffic
Traffic congestion is represented on the route line by different colors. By default there is an abrupt transition from one color to the next. The MapboxRouteLineViewOptions
class includes an option to display a gradient transition between the colors instead.
There is also an option to influence the length of the gradient transition. A higher value will result in a gradient over a longer length. A smaller value will result in a gradient that is shorter in length. In general, the softGradientTransition
option should be a value between 5.0 and 75.0.
val routeLineViewOptions = MapboxRouteLineViewOptions.Builder(context)
.displaySoftGradientForTraffic(true)
.softGradientTransition(30.0)
.build()
Update style at runtime
The route line UI component allows for changing a subset of MapboxRouteLineViewOptions
at runtime without recreating MapboxRouteLineView
or MapboxRouteLineApi
. The specific options that can be changed dynamically are defined in the MapboxRouteLineViewDynamicOptionsBuilder
class.
routeLineView.updateDynamicOptions(style) {
routeLineColorResources(newColors)
// ...
}
routeLineApi.getRouteDrawData {
routeLineView.renderRouteDrawData(style, it)
}