Getting started
Request a route, show it on a navigation map, and start simulated guidance:
import { useEffect, useState } from 'react';
import { Text, View } from 'react-native';
import Mapbox, { Camera, MapView } from '@rnmapbox/maps';
import Navigation, {
NAVIGATION_MAP_VIEW_IMPL,
NavigationViewport,
type Position,
type Route,
type RouteProgressEvent,
} from '@rnmapbox/navigation';
const ACCESS_TOKEN = 'pk....';
Mapbox.setAccessToken(ACCESS_TOKEN);
Navigation.setAccessToken(ACCESS_TOKEN);
const ORIGIN: Position = [-122.39726, 37.79205]; // [longitude, latitude]
const DESTINATION: Position = [-122.39351, 37.79554];
export function NavigationScreen() {
const [progress, setProgress] = useState<RouteProgressEvent>();
useEffect(() => {
const subscription = Navigation.addRouteProgressListener(setProgress);
let route: Route | undefined;
let cancelled = false;
Navigation.requestRoutes({ waypoints: [ORIGIN, DESTINATION] })
.then(({ main, alternatives }) => {
alternatives.forEach((alternative) => alternative.release());
route = main;
if (cancelled) {
main.release();
return;
}
// Switches the camera to 'following'.
return Navigation.startActiveGuidance(main, { simulate: true });
})
.catch((error) => console.warn(error));
return () => {
cancelled = true;
subscription.remove();
Navigation.stopNavigation();
route?.release();
};
}, []);
return (
<View style={{ flex: 1 }}>
<MapView style={{ flex: 1 }} mapViewImpl={NAVIGATION_MAP_VIEW_IMPL}>
<Camera defaultSettings={{ centerCoordinate: ORIGIN, zoomLevel: 14 }} />
{/* Keeps the puck and the route clear of UI drawn over the map. */}
<NavigationViewport
padding={{ top: 16, bottom: 120, left: 16, right: 16 }}
/>
</MapView>
{progress && (
<Text>
{progress.maneuverInstruction} in{' '}
{Math.round(progress.stepDistanceRemaining)} m
</Text>
)}
</View>
);
}
Navigation.previewRoute(route) shows a route on navigation maps before guidance starts, and Navigation.setCameraState('overview') fits the rest of the route.
The headless API has no arrival event in the current release; one is in progress in rnmapbox/navigation#9. <NavigationView> reports arrivals with onArrive.
Routes
requestRoutes resolves to { main, alternatives }. A Route is backed by the native SDK route and holds native memory:
- Its getters (
distance,expectedTravelTime,geometry,legs) read a copy taken when the route was created. They're synchronous. release()frees the native route. Release the routes you don't keep, such as unused alternatives. The garbage collector releases the rest eventually, but it doesn't see the native memory, so that can take long.- After
release(), reading anything butisReleasedthrows anErrorwithcode: 'route_released', andstartActiveGuidanceandpreviewRoutereject or throw it. - Guidance and the preview keep their own reference to the native route until
stopNavigation, so releasing a route they use is safe. - Routes don't survive a JS reload.
Navigation maps
<MapView mapViewImpl={NAVIGATION_MAP_VIEW_IMPL}> is a regular @rnmapbox/maps map: its props, children and events keep working. The Navigation SDK also draws the route line and the puck on it and drives its camera.
There's one navigation session per app. Every navigation map shows its route, puck and camera state. Without guidance the maps show the route passed to previewRoute.
<NavigationViewport> configures the map it's a child of. Its padding is in points from the map's edges and ignores the safe area. It applies to following, overview and the route preview. Without it the SDK defaults apply: the safe area plus a small margin on iOS, and no padding on Android.
Camera
| State | Camera |
|---|---|
following | Follows the puck, tilted and rotated with the route. Set by startActiveGuidance. |
overview | Fits the rest of the route. |
idle | Left alone, for the user's gestures and @rnmapbox/maps Camera. |
The state switches to idle when a pan, pinch, rotate, pitch or double-tap gesture happens on any navigation map, when an @rnmapbox/maps Camera moves the map from its props or setCamera (defaultSettings doesn't count), and when stopNavigation is called.
addCameraStateListener reports every change, and getCameraState returns the current state. Call setCameraState('following') to recenter.
- On Android a
Cameramove withanimationDuration: 0doesn't switch the state, and the navigation camera takes the map back at the next location update. Animate the move, or callsetCameraState('idle')first. CamerafollowUserLocationand the navigation camera both drive the map. Don't combine them.
After stopNavigation, the route and the puck are removed and the camera eases back to north-up, without tilt or padding.