Flutter Native - Itinerary
This guide explains how to add, display, and manage itineraries (routes) on the Wemap map. Itineraries are indoor/outdoor routes computed by the Wemap backend—from user location or chosen points to a destination. You can customize search rules (e.g. wheelchair-accessible) and listen to itinerary events. To start turn-by-turn navigation along an itinerary, see Navigation.
Overview
The itinerary feature lets you:
- Add an itinerary — From user location, map center, or custom origin to a destination
- Display the route — The route is drawn on the map automatically
- Show the itinerary panel — Optional built-in
ItineraryWidgetwith duration, arrival time, and a button to start navigation
Typical flow: user selects a POI → taps "Go there" in DetailedView → itinerary is added → ItineraryWidget appears → user taps "Start" to begin navigation (see Navigation).
Adding itineraries
All itinerary methods are on MapManager, available in onMapReady:
WemapMap(
options: MapOptions(...),
onMapReady: (MapData mapData, MapManager mapManager) {
// Use mapManager for itineraries
},
)
1. From user location
Use when the start point is the user's current position (GPS or VPS). If location is unknown, locateMe is called automatically (or VPS scan is triggered with VPS).
Permissions: Methods with
FromUserLocationneed location permission (GPS) or camera permission (VPS) granted before calling. Request permissions first—see GPS and VPS.
await mapManager.addItineraryFromUserLocation(
destination: Coordinate(
latitude: 48.876,
longitude: 2.323,
level: 0,
),
);
With search rules and optional color:
await mapManager.addItineraryFromUserLocation(
destination: poi.coordinate,
searchRules: ItinerarySearchRules(ruleNames: ["wheelchair"]),
color: Colors.blue,
updateUserLocation: false, // true to force re-locate before computing
);
VPS note: If the user is not yet localized, passing updateUserLocation: true triggers a scan. The itinerary is added once localization succeeds.
2. From map center
Use when the user chooses a point on the map as the start (e.g. by moving and zooming).
await mapManager.addItineraryFromMapCenter(
destination: poi.coordinate,
searchRules: ItinerarySearchRules(ruleNames: ["wheelchair"]),
color: Colors.green,
);
3. From explicit origin to destination
Use when both start and end are known coordinates:
await mapManager.addItinerary(
origin: Coordinate(latitude: 48.877, longitude: 2.324, level: 0),
destination: Coordinate(latitude: 48.876, longitude: 2.323, level: 1),
searchRules: ItinerarySearchRules(),
color: Colors.red,
);
Removing itineraries
To clear the current itinerary and route from the map:
await mapManager.removeItinerary();
Search rules (accessibility & constraints)
Search rules influence how the route is computed (e.g. avoiding stairs, prefer elevators).
Wheelchair (PRM) rule
searchRules: ItinerarySearchRules.WHEELCHAIR
Custom rule names
Rules are map-specific. Get available rule names from the current map:
final ruleNames = await mapManager.searchRuleNames();
// e.g. ["wheelchair", "avoid_escalators", "prefer_elevator", ...]
Use them when adding an itinerary:
await mapManager.addItineraryFromUserLocation(
destination: destination,
searchRules: ItinerarySearchRules(ruleNames: ["avoid_escalators", "prefer_elevator"]),
);
Callbacks
Listen to itinerary events via WemapMap:
| Callback | When triggered |
|---|---|
onItineraryAdded | Itinerary computed and added to map |
onItineraryRemoved | Itinerary removed |
onItineraryFailed | Itinerary computation failed (e.g. no route found) |
WemapMap(
options: MapOptions(...),
onItineraryAdded: (Itinerary itinerary) {
print('Route: ${itinerary.distance}m, ${itinerary.duration}s');
},
onItineraryRemoved: () {
print('Itinerary cleared');
},
onItineraryFailed: (String error) {
print('Failed: $error');
// Show error to user (e.g. "No route to this point")
},
)
Itinerary model
The Itinerary object returned in onItineraryAdded contains:
| Field | Type | Description |
|---|---|---|
from | Coordinate | Start point |
to | Coordinate | End point |
duration | double | Total duration in seconds |
distance | double | Total distance in meters |
legs | List<Leg> | Route legs |
Each Leg has duration, distance, and steps. Each Step includes:
name,number,distance,duration,isLastStepkind—Kindenum:STAIRS,ELEVATOR,ESCALATOR,TURN,CONTINUE, etc.direction—Directionenum:LEFT,RIGHT,STRAIGHT,UP,DOWN, etc.navInstructions— Turn-by-turn instructions
Built-in itinerary UI
| Option | Description |
|---|---|
itineraryWidgetEnabled: true | Shows ItineraryWidget when an itinerary is added — duration, arrival time, start/end, PRM toggle, rules panel, back button, and "Start" to begin navigation |
detailedViewEnabled: true | Enables "Go there" button in POI detail view, which triggers addItineraryFromUserLocation |
See Widgets for screenshots. To start navigation when the user taps "Start", see Navigation.
Custom integration (no built-in ItineraryWidget)
You can handle itineraries entirely in your own UI:
// 1. Add itinerary when user selects a destination
mapManager.addItineraryFromUserLocation(destination: selectedPOI.coordinate);
// 2. React to success/failure
onItineraryAdded: (Itinerary itinerary) {
setState(() {
_currentItinerary = itinerary;
_showCustomRoutePanel = true;
});
},
onItineraryFailed: (String error) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(error)));
},
// 3. Your custom "Start" button — starts turn-by-turn
ElevatedButton(
onPressed: () => mapManager.startNavigationWithCurrentItinerary(),
child: Text('Start'),
)
Coordinate and level
For indoor maps, include level in Coordinate when known:
Coordinate(
latitude: 48.876,
longitude: 2.323,
level: 1, // Floor level
)
Complete example
WemapMap(
options: MapOptions(
mapID: yourMapId,
token: yourToken,
environment: Environment.PROD
),
detailedViewEnabled: true,
itineraryWidgetEnabled: true,
onMapReady: (mapData, mapManager) async {
_mapManager = mapManager;
_availableRules = await mapManager.searchRuleNames();
// Optionally add itinerary programmatically:
// await mapManager.addItinerary(
// origin: somePOI.coordinate,
// destination: anotherPOI.coordinate,
// searchRules: ItinerarySearchRules(ruleNames: ["wheelchair"]),
// );
},
onItineraryAdded: (itinerary) {
print('Added: ${itinerary.duration}s, ${itinerary.distance}m');
},
onItineraryFailed: (error) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(error)));
},
)
Troubleshooting
| Issue | Solution |
|---|---|
FromUserLocation methods fail or hang | Grant location (GPS) or camera (VPS) permission before calling; see GPS and VPS |
No route found / onItineraryFailed | Destination may be unreachable; try different searchRules or ensure user/destination are on the map graph |
| Itinerary not drawn | Ensure addItinerary* completed successfully and onItineraryAdded fired |
| "Go there" does nothing | Enable detailedViewEnabled; check location permission (GPS) or VPS state |
| Rules not applied | Use mapManager.searchRuleNames() to get valid rule names for your map |