Skip to main content

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:

  1. Add an itinerary — From user location, map center, or custom origin to a destination
  2. Display the route — The route is drawn on the map automatically
  3. Show the itinerary panel — Optional built-in ItineraryWidget with 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 FromUserLocation need 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:

CallbackWhen triggered
onItineraryAddedItinerary computed and added to map
onItineraryRemovedItinerary removed
onItineraryFailedItinerary 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:

FieldTypeDescription
fromCoordinateStart point
toCoordinateEnd point
durationdoubleTotal duration in seconds
distancedoubleTotal distance in meters
legsList<Leg>Route legs

Each Leg has duration, distance, and steps. Each Step includes:

  • name, number, distance, duration, isLastStep
  • kindKind enum: STAIRS, ELEVATOR, ESCALATOR, TURN, CONTINUE, etc.
  • directionDirection enum: LEFT, RIGHT, STRAIGHT, UP, DOWN, etc.
  • navInstructions — Turn-by-turn instructions

Built-in itinerary UI

OptionDescription
itineraryWidgetEnabled: trueShows ItineraryWidget when an itinerary is added — duration, arrival time, start/end, PRM toggle, rules panel, back button, and "Start" to begin navigation
detailedViewEnabled: trueEnables "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

IssueSolution
FromUserLocation methods fail or hangGrant location (GPS) or camera (VPS) permission before calling; see GPS and VPS
No route found / onItineraryFailedDestination may be unreachable; try different searchRules or ensure user/destination are on the map graph
Itinerary not drawnEnsure addItinerary* completed successfully and onItineraryAdded fired
"Go there" does nothingEnable detailedViewEnabled; check location permission (GPS) or VPS state
Rules not appliedUse mapManager.searchRuleNames() to get valid rule names for your map