Routing module
The Routing module draws the routes calculateRoute returns, their
waypoints, guidance, traffic along the way, and the route-related interactions.
What this module owns: the route lines, waypoints, section overlays, instruction arrows and summary bubbles it draws, and how they look (Route styling). It never restyles the roads underneath, which belong to the Styling Foundations module. Two looks reach it from outside:
- A route given no
colortakes the map's accent. - Its traffic sections follow the Traffic Incidents module's
colors.*knobs (Borrowed looks).
No other knob reaches route layers — Who owns what.
Two features of the module have a guide of their own:
| Guide | Covers |
|---|---|
| Route styling | Colour, width, waypoint size, layers, the knob catalogue, layer positioning and charging stop icons |
| Route sections | The overlays drawn per stretch of road: tunnels, ferries, traffic, speed limit signs, border crossings and the rest |
Initialization
import { TomTomMap, RoutingModule } from '@tomtom-org/maps-sdk/map';
const map = new TomTomMap({ mapLibre: { container: 'map' } });
const routingModule = await RoutingModule.create(map, {
displayUnits: { distance: { type: 'metric' } }, // optional
waypoints: { entryPoints: 'main-when-available' } // optional
});
- Without
displayUnits, the labels follow the global units (TomTomConfig.instance.put({ displayUnits })) in force when they are drawn. A change reaches shown routes on their nextshowRoutesor configuration change. getConfig()returns only what you passed, never the global units.
Displaying routes
import { calculateRoute } from '@tomtom-org/maps-sdk/services';
const locations = [
[4.9041, 52.3676], // Amsterdam
[4.4777, 51.9244] // Rotterdam
];
const routes = await calculateRoute({ locations });
await routingModule.showRoutes(routes);
await routingModule.showWaypoints(locations); // showRoutes draws no pins
showRoutes draws the route line only; the start, stop and destination pins are showWaypoints's.
What locations takes is in Locations, every other request option in
Route planning parameters.
Displaying guidance on map
A route calculated with guidance: { type: 'coded' } draws its instruction
lines and arrows with no extra configuration:
const route = await calculateRoute({ locations, guidance: { type: 'coded' } });
await routingModule.showRoutes(route);
Route selection
With alternatives, one route is drawn as selected — the first unless told otherwise:
const routes = await calculateRoute({ locations, maxAlternatives: 2 });
await routingModule.showRoutes(routes, { selectedIndex: 1 });
await routingModule.selectRoute(0); // re-marks the shown routes, no recalculation
Waypoints
showWaypoints draws the pins, and clearWaypoints removes them; neither touches the routes, and
clearRoutes leaves the pins.
A stop's pin is labelled with its name and, when the stop carries a pauseDurationSeconds, how long the route
waits there, in the SDK's display units:
const locations = [
[2.1734, 41.3851],
{
type: 'Feature',
geometry: { type: 'Point', coordinates: [2.4467, 41.5381] },
properties: { pauseDurationSeconds: 30 * 60 } // the pin reads "30 min" under the stop name
},
[2.8214, 41.9794]
];
await routingModule.showRoutes(await calculateRoute({ locations }));
await routingModule.showWaypoints(locations);
Charging stop pins carry the same label: the whole time spent there, charging plus any wait asked for at the
same place. A label that wants only the charging part reads chargingDuration:
const routingModule = await RoutingModule.create(map, {
chargingStops: { label: { title: ['format', ['get', 'chargingDuration'], {}] } }
});
Waypoints or places
- A waypoint is every location a route is calculated through:
showWaypointsdraws it with its role (start, stop or finish), its stop mark and the module'swaypointsevents. - A place the user is still choosing among, such as a search result or a candidate stop, belongs to the
Places module. Once it joins the route, clear it there and hand it to
showWaypoints, so no location is drawn twice:
places.events.on('click', async (place) => {
const locations = [origin, place, destination];
await places.clear();
await routingModule.showRoutes(await calculateRoute({ locations }));
await routingModule.showWaypoints(locations);
});
A location several routing modules share, such as the one destination of routes from several origins, can be marked once by a Places module instead.
Everything below reaches the waypoints already shown when it changes through applyConfig, and they keep
their ids and event states. It is all live on the waypoints playground:
Pins per role
waypoints.icon.style styles every pin; waypoints.icon.start, middle and finish style one role each,
over it. A pin left without a fillColor takes the route's color:
const routingModule = await RoutingModule.create(map, {
waypoints: {
icon: {
style: { outlineColor: '#FFFFFF' },
start: { style: { fillColor: '#1B7A3E' } },
finish: { style: { fillColor: '#C0392B' } }
}
}
});
Stop marks
- A stop's pin carries its number among the stops, 1 for the first.
waypoints.stopNumberingsets'letters'(A to Z, then AA) or'none'. - The count includes the stops a mapping draws its own icon for, so the marks keep
matching the stop order; those icons, and a
middle.image, carry no mark. - The start and finish pins draw their own glyph instead.
- The mark is the waypoint's
stopDisplayLabelproperty, whichevents.waypointshandlers receive.
Labels
Each pin is labelled with its POI name, else its address, and its wait. waypoints.label.visible: false drops
the labels, and waypoints.label.title writes your own, as label.title does for
places — a function of the waypoint, or a MapLibre expression:
import { buildWaypointTitle } from '@tomtom-org/maps-sdk/map';
routingModule.applyConfig({
waypoints: {
label: {
title: (waypoint) => (waypoint.properties.indexType === 'finish' ? 'Home' : buildWaypointTitle(waypoint) ?? '')
}
}
});
The label's colour, halo and size are in Route styling.
Hover and click
Once a handler covers the waypoints, a hovered or clicked pin grows by waypoints.highlight.sizeFactor, its
stop mark with it: 1.2 times unless set, clamped to 1 to 1.5, and 1 draws it as any other. The waypoints
scope has the event state methods to put that state from your own UI:
routingModule.events.waypoints.on('hover', (waypoint) => showStopCard(waypoint.properties));
routingModule.events.waypoints.setEventState({ index: 1, state: 'click' });
Icons of your own
A role's image replaces its pin, and waypoints.icon.mapping picks a pin per waypoint from its data, as
icon.mapping does for places:
to: 'poiCategory'draws the SDK's pin for the categoryfnreturns, so a stop that came from search shows what kind of place it is.to: 'imageID'draws the imagefnnames: one in the style's sprite, or one ofwaypoints.icon.customIcons.- A waypoint
fnreturnsundefinedfor keeps its role's pin and stop mark.
const routingModule = await RoutingModule.create(map, {
waypoints: {
icon: {
finish: { image: { image: chequeredFlagSVG } },
mapping: { to: 'poiCategory', fn: (waypoint) => waypoint.properties.poi?.categories?.[0] }
}
}
});
- An image is drawn at pixel ratio 2 unless it sets
pixelRatio, standing on the waypoint by its bottom middle, as the SDK's 120 × 140 pixel pins do. RoutingModuleSerializableConfigkeeps the styles, the stop numbering and images given as a URL, data URI or SVG text; it leaves outmapping, a functiontitleand anHTMLImageElementimage.
Showing and hiding
setVisible(false) hides everything the module draws — route lines, waypoints, sections, guidance, charging
stops, summary bubbles and border crossings — and keeps what it shows:
const routingModule = await RoutingModule.create(map, { visible: false }); // starts hidden
await routingModule.showRoutes(route); // kept, not drawn
routingModule.setVisible(true); // draws the route
routingModule.isVisible(); // true
showRoutes,showWaypoints, the clear methods and a style change leave a hidden module hidden.- It is the config's
visible, soisVisible()reads the setting back andconfig-changereports it. - While the module is shown, each part's own
visible(sections.<type>.visible,summaryBubbles.visible, …) still decides whether that part draws.
Events
Each part of a route has a scope of its own, on the user events surface:
routingModule.events.mainLines.on('click', (route, lngLat) => console.log(route.properties));
routingModule.events.waypoints.on('click', (waypoint) => console.log(waypoint.properties.indexType));
routingModule.events.incidents.on('hover', (section) => console.log(section.properties.delayInSeconds));
routingModule.events.instructionLines.on('click', (instruction) => console.log(instruction.properties));
routingModule.events.summaryBubbles.on('click', (summary) => console.log(summary.properties));
routingModule.events.chargingStops.on('click', (stop) => console.log(stop.properties));
// Removes every click handler of the scope; `on` returns an unsubscribe for one handler
routingModule.events.mainLines.off('click');
- The section scopes —
ferries,tollRoads,tunnels,vehicleRestricted,countryCrossingsand one<type>Sectionsper generated type — are in Route sections. - The instruction arrows have no scope: a click on one is a click on its instruction.
A hovered or clicked route draws its outline wider, selected or not, once a handler covers the routes. The
module's event state methods act on the routes, and each named scope has
them for its own features. A click marks the route; selectRoute makes it the selected one:
routingModule.events.mainLines.on('click', (route) => routingModule.selectRoute(route.properties.index));
routingModule.setEventState({ index: 1, state: 'hover' });
const { click: [clickedRouteID] = [] } = routingModule.getEventStates();
highlight.outline.widthFactor sets how much wider: 1.2 times unless set, clamped to 1 to 1.25 so the outline
never covers a section halo beneath the route, and 1 draws a hovered
route as any other. An outline width given through layers.mainLines.routeOutline is drawn as given, in every
state.
routingModule.applyConfig({ highlight: { outline: { widthFactor: 1.25 } } });
Multiple module instances
Each instance has its own sources, layers, configuration and events, for comparing route types or showing routes for several users:
const carRoutes = await RoutingModule.create(map, { color: '#2ECC71' });
const truckRoutes = await RoutingModule.create(map, { color: '#E67E22' });
await carRoutes.showRoutes(carRoute);
await truckRoutes.showRoutes(truckRoute);
Reading shown data
getShown() returns what the module draws, as prepared for display, split by what draws it:
const shown = routingModule.getShown();
if (shown.mainLines.features.length > 0) {
console.log(`Showing ${shown.mainLines.features.length} routes, ${shown.waypoints.features.length} waypoints`);
}
Its entries: mainLines, waypoints, incidents, ferries, chargingStops, tollRoads, tunnels,
vehicleRestricted, instructionLines, instructionArrows, summaryBubbles and countryCrossings, plus one
<type>Sections per generated section type —
urbanSections, motorwaySections and the rest.
API reference
RoutingModule and
RoutingModuleConfig.
Related guides and examples
Services integration
- Route planning parameters - Every option of
calculateRoute - Locations - Specifying route planning locations
- Guidance - The turn-by-turn instructions the module draws
- Geocoding - Addresses to coordinates for waypoints and destinations
Related examples
- Route - Basic route calculation and display on the map
- Route with alternatives - Display multiple route options for comparison
- Waypoints - Multi-stop route visualization with interactive waypoints
- Map route reconstruction playground - Interactive route building and editing
- Route stop wait playground - A stop's wait on its pin, and in the journey time
- Route style playground - The route's colour, width, waypoint size, waypoint label colour and clicked outline on knobs, and a toggle that hides it
- Route sections playground - Every section type on one set of knobs, and the speed-limit sign controls
- Route waypoints playground - Per-role pins, stop numbering, labels, hover growth, a category pin per stop and a finish image of your own
- Speed limit signs by country - A section's number posted as the road sign its country uses
- Borrowed looks - A route's traffic sections recoloured live by the incident colour knobs
Related map modules
- Route styling - The route's own look and its knob catalogue
- Route sections - The overlays drawn per stretch of road
- Places module - The places a user is still choosing among, before one joins the route as a waypoint
- User interaction events - Handle user interactions with routes and route segments