Skip to main content

Navigation camera

The Mapbox Navigation SDK for Android includes a set of tools that let you combine the current user location information with the active route geometry to continuously track user movement and frame upcoming maneuvers.

In the Navigation SDK, there are two parts to managing the camera: specifying a data source and passing that data to the navigation camera. The SDK's MapboxNavigationViewportDataSource produces the data in form of map camera targets, and NavigationCamera consumes and executes that data to determine the camera's behavior.

Mapbox Maps SDK for Android
This functionality uses the Mapbox Maps SDK for Android. Read more in the Maps guide.

Specify the data source

The Navigation SDK exposes a ViewportDataSource interface and its default implementation of MapboxNavigationViewportDataSource. The viewport data source produces two types of CameraOptions objects encapsulated in the ViewportData object:

  • cameraForFollowing: frames the user location in the following mode
  • cameraForOverview: frames the remaining part of the route in the overview mode

Initialize data source

To initialize the default viewport data source, create an instance of MapboxNavigationViewportDataSource and pass it your map:

// initialize Viewport Data Source
viewportDataSource = MapboxNavigationViewportDataSource(mapboxMap)

Provide data

For the viewport data source to produce meaningful camera positions, you need to provide the location, route, or route progress data. Do this by calling a set of methods with available data updates.

For route updates, use RoutesObserver:

private val routesObserver = RoutesObserver { routes ->
if (routes.isNotEmpty()) {
viewportDataSource.onRouteChanged(routes.first())
viewportDataSource.evaluate()
} else {
viewportDataSource.clearRouteData()
viewportDataSource.evaluate()
}
}

For location updates, use LocationObserver:

private val locationObserver = object : LocationObserver {
override fun onRawLocationChanged(rawLocation: Location) {
// not handled
}
override fun onEnhancedLocationChanged(
enhancedLocation: Location,
keyPoints: List<Location>
) {
viewportDataSource.onLocationChanged(enhancedLocation)
viewportDataSource.evaluate()
}
}

For route progress updates, use RouteProgressObserver:

private val routeProgressObserver = RouteProgressObserver { routeProgress ->
viewportDataSource.onRouteProgressChanged(routeProgress)
viewportDataSource.evaluate()
}

Whenever you provide a new piece of data, remember to call MapboxNavigationViewportDataSource#evaluate so that the camera targets stored in the ViewportData are regenerated and relevant observers are called. With the continuous stream of latest location and routing data the class will be able to keep producing relevant camera targets to best frame the available geometries.

Initialize the viewport data source before usage
By itself, the MapboxNavigationViewportDataSource has no access to location or route data and will initialize at coordinates (0.0, 0.0). Make sure to manually initialize the source with the latest available user location update before executing any transitions.

The MapboxNavigationViewportDataSource can work with and without a route object, both for free-drive and turn-by-turn navigation experiences. When the route reference is available, it will continuously change zoom level to frame the upcoming maneuver together with the user location. When there's no route, it will stay at a constant zoom level while tracking the user location.

Clear route reference when switching between types of navigation
Whenever an Active Guidance trip finishes, make sure to call MapboxNavigationViewportDataSource#clearRouteData and then MapboxNavigationViewportDataSource#evaluate to remove route and route progress context from camera targets calculations.

Customize the data source

The viewport data source is one of the main contributors to how your navigation experience will be presented on the map.

Padding

You can provide padding for both the following and overview frames, which will make sure that framed geometries will be presented at the designated space on the map and not overlap with other UI elements, for example:

val pixelDensity = context.resources.displayMetrics.density
viewportDataSource.followingPadding = EdgeInsets(
180.0 * pixelDensity,
40.0 * pixelDensity,
150.0 * pixelDensity,
40.0 * pixelDensity
)
viewportDataSource.overviewPadding = EdgeInsets(
140.0 * pixelDensity,
40.0 * pixelDensity,
120.0 * pixelDensity,
40.0 * pixelDensity
)

Make sure to use pixel-density adjusted padding values to have a consistent experience on different devices.

Overview frame

The padded overview frame will contain the entirety of the route provided via MapboxNavigationViewportDataSource#onRouteChanged (or the rest of the current leg if MapboxNavigationViewportDataSource#onRouteProgressChanged is also available) and any additional points you've specified using MapboxNavigationViewportDataSource#additionalPointsToFrameForOverview.

Following frame

For the following frame, the first point of the framed geometry list will be placed at an offset from the center of this padding, specified by the FocalPoint. This typically refers to the user's location provided via MapboxNavigationViewportDataSource#onLocationChanged, if available. The first points positioning can be influenced by FollowingFrameOptions.maximizeViewableGeometryWhenPitchZero when there are at least two points available for framing.

Controlling user location indicator position on screen

When following frame is used and user location samples are provided to the viewport data source, you can control the position of the user location indicator on screen by:

  • Changing the size of the padding and in consequence its center.
  • Updating the focal point's x and y factors, where, for example, (x=0, y=0) positions the user location indicator in the top left of the padding, (x=0.5, y=0.5) positions it in the center of the padding, and (x=1.0, y=1.0) positions it in the bottom right of the padding. Read more on how to update the FocalPoint in the Options section.
Positioning the focal point on an edge of the padding
Whenever the FocalPoint's x or y components are set to either 0.0 or 1.0, the user location indicator will be placed on edge of the padding. In this case, the SDK will ignore all geometries that are beyond that edge based on camera's bearing when computing the new camera position, because there's no space between the focal point and the edge of the padding to fit them.

The frame will contain the remaining part of the current LegStep of the route provided via MapboxNavigationViewportDataSource#onRouteChanged. If the RouteProgress is not available, the frame will focus on the location sample from MapboxNavigationViewportDataSource#onLocationChanged with FollowingFrameOptions.maxZoom zoom and FollowingFrameOptions.defaultPitch.

Options

You can adjust the way location and geometries are framed within the padding by changing the MapboxNavigationViewportDataSourceOptions, which are accessible via MapboxNavigationViewportDataSource#options. For example, to change the default pitch during following:

viewportDataSource.options.followingFrameOptions.defaultPitch = 35.0
viewportDataSource.evaluate()

To understand all possible camera behaviors, see the available properties for both FollowingFrameOptions and OverviewFrameOptions.

Set up the navigation camera

NavigationCamera is a class that simplifies management of the map's camera object in typical navigation scenarios. It ingests camera targets produced by the ViewportDataSource and executes map camera transitions to those targets.

EXAMPLE
Example of Navigation Camera integration

Learn how to integrate NavigationCamera together with the MapboxNavigationViewportDataSource and their data streams in a navigation app.

Initialize navigation camera

To initialize the navigation camera, create an instance of NavigationCamera and pass it your map, camera, and viewport data source:

// initialize Navigation Camera
navigationCamera = NavigationCamera(
mapboxMap,
binding.mapView.camera,
viewportDataSource
)

Camera state

NavigationCamera maintains a state of any of the following:

enum class NavigationCameraState {
IDLE,
TRANSITION_TO_FOLLOWING,
FOLLOWING,
TRANSITION_TO_OVERVIEW,
OVERVIEW
}

You can change the camera state at any time by calling either requestNavigationCameraToFollowing() or requestNavigationCameraToOverview(), and executing camera transitions.

navigationCamera.requestNavigationCameraToFollowing()
navigationCamera.requestNavigationCameraToOverview()

NavigationCamera does not produce any camera position values, the positions that the camera should transition to are generated by the ViewportDataSource interface. The default implementation of that interface is described above.

Provide data before executing transitions
The default MapboxNavigationViewportDataSource initializes empty. Make sure to first provide the data to the viewport data source, check it, and only then request a following or overview state with NavigationCamera.

Once NavigationCamera is in a following or overview state, it will keep listening for updates from the viewport data source and execute transitions to new targets whenever the data source is evaluated.

To stop listening for updates, use requestNavigationCameraToIdle():

navigationCamera.requestNavigationCameraToIdle()

Debugging

Experimental feature
This feature is experimental and subject to change.

Use MapboxNavigationViewportDataSourceDebugger to attach a debugger to both MapboxNavigationViewportDataSource and NavigationCamera that will draw on top of the map the padding values and geometries that the viewport data source tries to frame.

val debugger = MapboxNavigationViewportDataSourceDebugger(
context,
mapView,
layerAbove = "road-label"
).apply {
enabled = true
}
viewportDataSource = MapboxNavigationViewportDataSource(
mapView.getMapboxMap()
)
viewportDataSource.debugger = debugger
navigationCamera = NavigationCamera(
mapView.getMapboxMap(),
mapView.camera,
viewportDataSource
)
navigationCamera.debugger = debugger

For the correct operation, the same exact instance of the MapboxNavigationViewportDataSourceDebugger has to be provided to both the MapboxNavigationViewportDataSource and NavigationCamera.

Was this page helpful?