This is the documentation of version 1.0.0-rc.3. Go to the latest version, 1.0.0-rc.5.

Routes

These helpers read a calculated route. They find where a new stop fits among the existing ones, a section's bounds, the stretches each route has to itself, the main roads it takes and how it differs from another route, the lanes to take into a maneuver, and the distance, time and position at any point along it. The examples below share this setup:

import { calculateRoute } from '@tomtom-org/maps-sdk/services';

const routes = await calculateRoute({ locations: [[4.9, 52.3], [5.1, 52.5]] });
const route = routes.features[0];
const waypoints = [[4.9, 52.3], [5.1, 52.5]];

Inserting waypoints

All four helpers project the stops onto the route line and place each new one by where it falls along the route. Waypoints are any WaypointLike: a [longitude, latitude], a GeoJSON Point or a Point feature such as a place.

Helper Takes Returns
withInsertedWaypoint one new stop a new array with it inserted
withInsertedWaypoints several new stops a new array with all of them inserted, in along-route order
findBestWaypointInsertionIndex one new stop the index to insert it at
findBestWaypointInsertionIndices several new stops one index per stop, in input order

withInsertedWaypoint

import { withInsertedWaypoint } from '@tomtom-org/maps-sdk/core';

const updated = withInsertedWaypoint(route, waypoints, [4.95, 52.35]);
// [[4.9, 52.3], [4.95, 52.35], [5.1, 52.5]]

const updatedRoutes = await calculateRoute({ locations: updated });

withInsertedWaypoints

withInsertedWaypoints inserts every new stop in one pass. Each goes to its slot between existing waypoints. Stops that share a slot follow the order in which they fall along the route. Ties keep their input order. Use it, for example, to merge the places discoverPlaces finds along a route:

import { withInsertedWaypoints } from '@tomtom-org/maps-sdk/core';

// Passed in any order; returned in along-route order
const updated = withInsertedWaypoints(route, waypoints, [[5.05, 52.45], [4.95, 52.35]]);
// [[4.9, 52.3], [4.95, 52.35], [5.05, 52.45], [5.1, 52.5]]

An empty list of new stops returns a copy of waypoints.

findBestWaypointInsertionIndex

import { findBestWaypointInsertionIndex } from '@tomtom-org/maps-sdk/core';

findBestWaypointInsertionIndex(route, waypoints, [4.95, 52.35]); // 1: between origin and destination

findBestWaypointInsertionIndices

import { findBestWaypointInsertionIndices } from '@tomtom-org/maps-sdk/core';

findBestWaypointInsertionIndices(route, waypoints, [[5.05, 52.45], [4.95, 52.35]]); // [1, 1]

Several stops can share a slot. withInsertedWaypoints also orders them within it.

getSectionBBox

The bounding box of a route section, or any { startPointIndex, endPointIndex }, from its start, middle and end points:

import { getSectionBBox } from '@tomtom-org/maps-sdk/core';

for (const section of route.properties.sections.country ?? []) {
    const bbox = getSectionBBox(route, section);
    if (bbox) map.mapLibreMap.fitBounds(bbox, { padding: 40 });
}

Returns BBox | undefined: undefined when the route has no coordinates, or the section's indices fall outside them or are reversed. Three points are fast, but a winding section can stray outside their box. For a tighter box, pass the section's slice of coordinates as a LineString to bboxFromGeoJSON.

getSectionOverlap

The stretch two sections of one route share, whatever their types, such as the tolls you pay in one country:

import { getSectionOverlap } from '@tomtom-org/maps-sdk/core';

const { country = [], toll = [] } = route.properties.sections;
const france = country.find((section) => section.countryCodeISO3 === 'FRA');
const tollsInFrance = france ? toll.filter((section) => getSectionOverlap(section, france)) : [];

Returns RouteSpan | undefined, the shared { startPointIndex, endPointIndex }: undefined when the sections share no segment, as two sections meeting at one point don't.

getDistinctSections

The stretches of each route that none of the other routes drives, which is what sets an alternative apart. calculateRoute already puts every one of them in sections.distinct when it returns two or more routes. To compare routes from separate calculations, or to keep only the stretches worth naming, call getDistinctSections. Routes match on a road where they carry the same coordinates along it, as the routes of one response do; routes from separate calculations may not.

import { formatDistance, getDistinctSections } from '@tomtom-org/maps-sdk/core';

const alternatives = await calculateRoute({ locations: waypoints, maxAlternatives: 2 });
getDistinctSections(alternatives, { minLengthInMeters: 1000 }).forEach((sections, index) => {
    const ownMeters = sections.reduce((total, section) => total + section.lengthInMeters, 0);
    console.log(`Route ${index}: ${formatDistance(ownMeters)} of its own`);
});

getImportantRoads

The motorways and main roads a route takes, by road number and street name, which is how a driver tells routes apart. Pass a route's distinct sections as within to name the roads only that route takes:

import { getImportantRoads } from '@tomtom-org/maps-sdk/core';

for (const route of alternatives.features) {
    const roads = getImportantRoads(route, { within: route.properties.sections.distinct, minLengthInMeters: 2000 });
    console.log(`via ${roads.map((road) => road.name).filter(Boolean).join(', ')}`);
}

getSectionsWithin

A route's sections of every type within spans of it, such as the ferries, tolls and traffic on the roads only that route takes:

import { formatDistance, getSectionsWithin } from '@tomtom-org/maps-sdk/core';

for (const route of alternatives.features) {
    const own = getSectionsWithin(route, { within: route.properties.sections.distinct, types: ['ferry', 'toll', 'traffic'] });
    if (own.ferry) console.log(`Route ${route.properties.index} takes a ferry for ${formatDistance(own.ferry.lengthInMeters)}`);
}

compareRoutes

How a route differs from a reference route: what it takes on, and what it stays clear of. For example, weigh an alternative against the route a user selected:

import { compareRoutes, formatDistance } from '@tomtom-org/maps-sdk/core';

const [selected, alternative] = (await calculateRoute({ locations: waypoints, maxAlternatives: 1 })).features;
// The service can return fewer alternatives than asked for
if (alternative) {
    const { adds, avoids } = compareRoutes(alternative, selected, { types: ['ferry', 'toll'] });
    if (avoids.toll) console.log(`Avoids ${formatDistance(avoids.toll.lengthInMeters)} of tolls`);
}

To tell why the fastest route goes the way it does, compare it with the route typical traffic would take. A route calculated with costModel: { traffic: 'historical' } still carries the live traffic along it, so the comparison names the jams and closures the live route avoids:

const [live, usual] = await Promise.all([
    calculateRoute({ locations: waypoints }),
    calculateRoute({ locations: waypoints, costModel: { traffic: 'historical' } }),
]);
const { avoids } = compareRoutes(live.features[0], usual.features[0], { types: ['traffic'] });
const closures = (avoids.traffic?.sections ?? []).filter((incident) => incident.categories.includes('road-closed'));

getInstructionLanes

Finds the lanes section leading to an instruction's maneuver, so you can show the lanes to take beside each step of a directions list. The routing module doesn't draw lanes on the map. calculateRoute returns lanes sections only when you request guidance.

import { getInstructionLanes } from '@tomtom-org/maps-sdk/core';

const guided = await calculateRoute({ locations: waypoints, guidance: { type: 'coded' } });
const guidedRoute = guided.features[0];
for (const instruction of guidedRoute.properties.guidance?.instructions ?? []) {
    const lanes = getInstructionLanes(guidedRoute, instruction);
    // lanes?.lanes lists each lane's directions, and the one to follow
}

Route progress

These helpers read the route's progress points, which routes have by default. Between two points, values follow the line's length rather than its vertex count, because vertices crowd into bends. Equal steps of distance cover equal ground, which is what an animation along the route needs.

calculateProgressAtRoutePoint

The distance and time from the start at a coordinate index:

import { calculateProgressAtRoutePoint } from '@tomtom-org/maps-sdk/core';

const progress = calculateProgressAtRoutePoint(route, 10);
// { distanceInMeters, travelTimeInSeconds } | undefined

Returns RouteProgressAtPoint | undefined: undefined when the index is out of range, the route has no progress, or the progress points around the index lack a value.

getRouteProgressBetween

The progress at two coordinate indices and the difference between them:

import { getRouteProgressBetween } from '@tomtom-org/maps-sdk/core';

const segment = getRouteProgressBetween(route, 5, 20);
if (segment) {
    console.log(`${segment.delta.distanceInMeters} m, ${segment.delta.travelTimeInSeconds} s`);
}

Returns RouteSegmentProgress | undefined: { start, end, delta }, or undefined when either index cannot be interpolated.

getRouteProgressForSection

getRouteProgressBetween over a section's startPointIndex and endPointIndex, or those of any { startPointIndex, endPointIndex }, such as the one getSectionOverlap returns:

import { getRouteProgressForSection } from '@tomtom-org/maps-sdk/core';

for (const section of route.properties.sections.traffic ?? []) {
    const progress = getRouteProgressForSection(route, section);
    if (progress) console.log(`Incident from ${progress.start.distanceInMeters} m, ${progress.delta.travelTimeInSeconds} s to cross`);
}

Returns RouteSegmentProgress | undefined, as getRouteProgressBetween does.

getCoordinateAtRouteProgress

The position and progress at a point you give as exactly one of elapsed time, distance travelled or a clock time.

import { getCoordinateAtRouteProgress } from '@tomtom-org/maps-sdk/core';

const byTime = getCoordinateAtRouteProgress(route, { traveledTimeInSeconds: 600 });
const byDistance = getCoordinateAtRouteProgress(route, { traveledDistanceInMeters: 5000 });
// Elapsed time counted from route.properties.summary.departureTime
const byClock = getCoordinateAtRouteProgress(route, { clockTime: new Date('2025-06-01T09:10:00Z') });

if (byTime) console.log(`After 10 min: ${byTime.position}, ${byTime.distanceInMeters} m`);

getProgressAtNearestRoutePoint

Snaps any location to the nearest point on the route and returns the position and progress there, for hover or click interactions:

import { formatDistance, getProgressAtNearestRoutePoint } from '@tomtom-org/maps-sdk/core';

map.mapLibreMap.on('mousemove', (event) => {
    const nearest = getProgressAtNearestRoutePoint(route, event.lngLat.toArray());
    if (nearest) console.log(`${formatDistance(nearest.distanceInMeters)} from the start`);
});