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

Traffic area analytics module

TrafficAreaAnalyticsModule draws a region's historical traffic from a trafficAreaAnalytics response as hexagon or square grids, flat or extruded, or as a density heatmap, with the region's boundary.

The module owns the grid and heatmap layers it renders and their look, which you set with the colour, height and layer-position configuration below. It never restyles the base map underneath, which belongs to the Styling Foundations module. In turn, styling knobs never touch these layers. See Who owns what.

Initialization

import { TomTomMap, TrafficAreaAnalyticsModule } from '@tomtom-org/maps-sdk/map';

const map = new TomTomMap({ mapLibre: { container: 'map' } });
const analyticsModule = await TrafficAreaAnalyticsModule.create(map, {
    displayMode: 'hexgrid-3d',
    activeMetric: 'congestionLevel',
    metrics: { congestionLevel: { palette: 'trafficLight' } },
});

Fetching and displaying data

Pass a trafficAreaAnalytics response to show() as it arrives. To switch metrics later without fetching again, ask for metrics: 'all':

import { geocodeOne, geometryData, trafficAreaAnalytics } from '@tomtom-org/maps-sdk/services';

const place = await geocodeOne('Amsterdam, Netherlands');
const boundary = await geometryData({ geometries: [place] });

const analytics = await trafficAreaAnalytics({
    apiKey: 'YOUR_MOVE_PORTAL_KEY',
    startDate: '2024-08-06',
    endDate: '2024-08-12',
    metrics: 'all',
    functionalRoadClasses: 'all',
    hours: 'all',
    geometry: boundary.features[0].geometry,
});

await analyticsModule.show(analytics);
await analyticsModule.clear(); // removes it again

Visualization modes

displayMode sets one of five modes, at create() or through updateConfig({ displayMode }):

Mode Draws
'hexgrid-3d' Hexagons coloured and raised by the metric (default)
'hexgrid-2d' Flat hexagons coloured by the metric
'square-3d' Squares coloured and raised by the metric
'square-2d' Flat squares coloured by the metric
'heatmap' A MapLibre density heatmap from the tile centres
analyticsModule.updateConfig({ displayMode: 'heatmap' });

Metrics

activeMetric picks the metric that colours and raises the cells, congestionLevel by default. Each metric's look (palette or colour stops, height, filters) sits under metrics.<metric>, so you can set up several and switch between them:

const analyticsModule = await TrafficAreaAnalyticsModule.create(map, {
    activeMetric: 'congestionLevel',
    metrics: {
        congestionLevel: { palette: 'trafficLight' },
        speed: { palette: 'heat' },
        travelTime: { height: { maxMeters: 300 } },
    },
});
analyticsModule.updateConfig({ activeMetric: 'speed' });

The metrics are areaAnalyticsMetricKeys, with the units of the service. On a tile, networkLength is the road length within that tile, which indicates road density.

Color

A metric takes its colours from metrics.<metric>.palette, a named palette, or metrics.<metric>.colorStops, your own stops.

Palettes

areaAnalyticsPalettes lists the names (AreaAnalyticsPalette). Each runs from good traffic to bad:

analyticsModule.setPalette('trafficLight'); // green → amber → red (default)
analyticsModule.setPalette('heat');         // blue → orange → red
analyticsModule.setPalette('monochrome');   // light grey → dark grey
analyticsModule.setPalette('viridis');      // yellow → green → blue → purple
analyticsModule.setPalette('plasma');       // yellow → orange → magenta → purple

analyticsModule.setPalette('viridis', ['speed', 'freeFlowSpeed']); // only these metrics

Custom color stops

setColorStops(), or colorStops in the config, takes an AreaAnalyticsColorStopsConfig. It holds the stops, each a value and a CSS color, and the scaleMode that says what the values are.

scaleMode A stop's value is
'raw' (default) a metric value
'predefinedRange' 0–100 % of the SDK's range for the metric: congestion 0–100, speed and free-flow speed 0–120 km/h, travel time 0–20 minutes per 10 km, network length 0–5000 m
'currentRange' 0–100 % of the range in the loaded tiles, 0 % being the loaded minimum

The heatmap colours its density, not a metric value, so it spreads the stops over that density whatever the scaleMode: 'predefinedRange' and 'currentRange' stops from 0 to 100, 'raw' stops from their lowest value to their highest.

analyticsModule.setColorStops({
    scaleMode: 'raw',
    stops: [
        { value: 0, color: '#2dc653' },   // 0 % congestion
        { value: 30, color: '#f5a623' },
        { value: 100, color: '#e03030' },
    ],
}, ['congestionLevel']);
analyticsModule.setColorStops(undefined); // back to the metric's palette
analyticsModule.setPalette(undefined);    // and with no palette, 'trafficLight'

Reading a metric's colours

resolveColorStops(metric, metricConfig) returns the stops a metric is painted with, as an AreaAnalyticsColorStopsConfig. These are its colorStops when they hold a stop, otherwise its palette spread from 0 to 100 % of its range, reversed on the speed metrics. A legend or chart drawn from it follows whatever the config sets:

import { resolveColorStops } from '@tomtom-org/maps-sdk/map';

const { scaleMode, stops } = resolveColorStops('speed', analyticsModule.getConfig()?.metrics?.speed);
const legendColors = stops.map((stop) => stop.color);

Height

In the 3D modes, metrics.<metric>.height (AreaAnalyticsHeightConfig) raises the cells. setHeight() sets every metric, or only those in its second argument.

analyticsModule.setHeight({ maxMeters: 200 });                   // cells up to 200 m
analyticsModule.setHeight({ maxMeters: 100, minMeters: 10 });    // and a floor
analyticsModule.setHeight({ scaleMode: 'currentRange', maxMeters: 150 }, ['speed']);
analyticsModule.setHeight({ scaleMode: 'raw', metersPerUnit: 10 });    // 10 m per unit of the metric
analyticsModule.setHeight(undefined, ['speed']);                 // back to its default height

Filtering

setFilters() hides the cells outside a value range, for every metric or only those in its second argument:

analyticsModule.setFilters({ min: 50 });                    // congestion ≥ 50
analyticsModule.setFilters({ min: 20, max: 80 }, ['congestionLevel']);
analyticsModule.setFilters(undefined);                      // clears them

Only the active metric's filter hides cells, and never in the heatmap.

Region boundary

show() draws each region polygon of the response alongside the cells, as a fill and an outline. regionPolygon styles it:

const analyticsModule = await TrafficAreaAnalyticsModule.create(map, {
    regionPolygon: {
        color: '#0052a5',                // fill and line; default black on a light style, white on a dark one
        // style 'inverted' tints the world outside the region; defaults 'filled' and opacity 0
        fill: { style: 'inverted', opacity: 0.08 },
        line: { opacity: 1, width: 3 },  // defaults 0.5 and 2 px
    },
});

Layer positioning

beforeLayerConfig (AreaAnalyticsBeforeLayerConfig) takes one target for every display mode ('top' or a key of mapStyleLayerIDs), or a record keyed by display mode, plus all for the modes it leaves out:

const analyticsModule = await TrafficAreaAnalyticsModule.create(map, {
    beforeLayerConfig: { all: 'lowestLabel', 'hexgrid-3d': 'lowestPlaceLabel', 'square-3d': 'lowestPlaceLabel' },
});
analyticsModule.updateConfig({ beforeLayerConfig: { 'hexgrid-3d': 'top' } });

Layer overrides

Beyond the settings above, layers (TrafficAreaAnalyticsLayersConfig) takes a partial MapLibre layer per layer the module draws. Each display mode draws its own:

Mode Layers
heatmap heatmap
hexgrid-2d hexgridFill, hexgridOutline (the outline of a hovered or clicked cell)
hexgrid-3d hexgridExtrusion, hexgridExtrusionHighlight
square-2d, square-3d the same four square* entries
every mode regionFill, regionLine
analyticsModule.updateConfig({
    layers: {
        hexgridFill: { paint: { 'fill-opacity': 0.85 } },
        hexgridExtrusion: { paint: { 'fill-extrusion-vertical-gradient': false } },
        regionLine: { paint: { 'line-dasharray': [2, 2] } },
    },
});

Visibility

isVisible() reports the visible setting, true by default, not whether any cell is drawn. Hiding keeps the data. While the module is hidden, show() updates the data without drawing it.

const analyticsModule = await TrafficAreaAnalyticsModule.create(map, { visible: false });
analyticsModule.setVisible(true);
analyticsModule.getShown().hexgrid.features.length > 0; // whether there are cells to draw

Events

click, hover, long-hover and the other user events fire on what the active mode draws: hexagon or square cells, or the heatmap's tile-centre points. The handler receives it as an AreaAnalyticsTileFeature, with its metric values in properties:

analyticsModule.events.on('click', (cell, lngLat) => {
    console.log(cell.properties.congestionLevel, cell.properties.speed);
});
analyticsModule.events.off('click');

The module highlights a hovered or clicked cell. Its event state methods highlight one from your own UI, or read which ones are:

analyticsModule.setEventState({ index: 0, state: 'click' });
const { click = [] } = analyticsModule.getEventStates();

Custom tooltip on hover

import { Popup } from 'maplibre-gl';

const popup = new Popup({ closeButton: false, anchor: 'left', offset: 12 });

analyticsModule.events.on('hover', (cell, lngLat) => {
    const { congestionLevel, speed } = cell.properties;
    popup
        .setLngLat(lngLat)
        .setHTML(`<strong>Congestion:</strong> ${congestionLevel ?? 0}%<br/><strong>Speed:</strong> ${speed ?? 0} km/h`)
        .addTo(map.mapLibreMap);
});

map.mapLibreMap.getCanvas().addEventListener('mouseleave', () => popup.remove());

Changing the configuration

analyticsModule.applyConfig({ displayMode: 'heatmap' }); // everything else back to its default
analyticsModule.updateConfig({ activeMetric: 'speed' }); // displayMode stays 'heatmap'
analyticsModule.setPalette('viridis', ['speed']);        // the other metrics keep their colours

Config change events

Every setter, applyConfig and updateConfig emit config-change, and each show() emits shown-features with the response (module events):

const unsubscribe = analyticsModule.events.on('config-change', (config) => {
    console.log('Active metric:', config?.activeMetric);
});

Querying shown features

getShown() returns the heatmap points and the hexgrid and square polygons the sources hold, whichever mode shows:

const { heatmap, hexgrid, square } = analyticsModule.getShown();
console.log(`Hexagonal cells: ${hexgrid.features.length}`);

Every setting as data

trafficAreaAnalyticsKnobCatalogue lists the module's plain-valued settings with their kind, range or options, and their default where one value holds everywhere. A UI can build its controls from it with no map loaded:

import { trafficAreaAnalyticsKnobCatalogue } from '@tomtom-org/maps-sdk/map';

const speedKnobs = trafficAreaAnalyticsKnobCatalogue.filter(({ id }) => id.startsWith('metrics.speed.'));
// [{ id: 'metrics.speed.palette', kind: 'enum', description: '…', options: ['trafficLight', 'heat', …], default: 'trafficLight' }, …,
//  { id: 'metrics.speed.filters.min', kind: 'number', description: '…', range: { min: 0, max: 120, bounds: 'hard-min' } }, …]

The module-wide knobs come first, then the same seven for each metric, where <metric> stands for any of areaAnalyticsMetricKeys:

Id Kind
visible toggle, true by default
displayMode enum, hexgrid-3d by default
activeMetric enum, congestionLevel by default
regionPolygon.color color, by default black on a light style, white on a dark one
regionPolygon.fill.style enum: filled, inverted
regionPolygon.fill.opacity, regionPolygon.line.opacity number, 0 to 1
regionPolygon.line.width number, 0 to 10 pixels
metrics.<metric>.palette enum: areaAnalyticsPalettes, default trafficLight
metrics.<metric>.height.scaleMode enum: predefinedRange, currentRange, raw
metrics.<metric>.height.maxMeters, metrics.<metric>.height.minMeters number, 0 to 5000 metres
metrics.<metric>.height.metersPerUnit number, 0 to 100 metres per unit of the metric, in the raw scale mode
metrics.<metric>.filters.min, metrics.<metric>.filters.max number, over the metric's predefined range

API reference

TrafficAreaAnalyticsModule, TrafficAreaAnalyticsModuleConfig and AreaAnalyticsMetricConfig.

Related guides and examples

Related guides

Related examples