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

Traffic Area Analytics Module

The Traffic Area Analytics Module visualizes historical traffic data for a geographic region on the map. Data is fetched from the TomTom Move Portal API and rendered using one of five visualization modes: 3D or flat hexagonal grids, 3D or flat square grids, or a density heatmap.

Initialization

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

const map = new TomTomMap({ mapLibre: { container: 'map' } });
const analyticsModule = await TrafficAreaAnalyticsModule.get(map);

Configure the module at initialization time using a config object:

const analyticsModule = await TrafficAreaAnalyticsModule.get(map, {
    displayMode: 'hexgrid-3d',
    activeMetric: 'congestionLevel',
    metricConfig: {
        congestionLevel: { color: 'trafficLight' },
    },
});

Fetching and Displaying Data

Fetch area analytics data using the trafficAreaAnalytics service and pass the response directly to show().

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

// 1. Geocode a city to get its boundary
const place = await geocodeOne('Amsterdam, Netherlands');
const boundary = await geometryData({ geometries: [place] });
const regionGeometry = boundary.features[0].geometry;

// 2. Fetch analytics for the last 7 days
const endDate = new Date();
endDate.setDate(endDate.getDate() - 2); // API requires at least 2 days ago
const startDate = new Date(endDate);
startDate.setDate(startDate.getDate() - 6);
const fmt = (d) => d.toISOString().slice(0, 10);

const analytics = await trafficAreaAnalytics({
    apiKey: MOVE_PORTAL_KEY,
    name: 'Amsterdam, Netherlands',
    startDate: fmt(startDate),
    endDate: fmt(endDate),
    metrics: 'all',
    functionalRoadClasses: 'all',
    hours: 'all',
    geometry: regionGeometry,
});

// 3. Display on the map
await analyticsModule.show(analytics);

To remove data from the map:

await analyticsModule.clear();

Visualization Modes

Five modes are available, set via displayMode at init time or changed at runtime with setMode():

Mode Description
'hexgrid-3d' 3D extruded hexagonal cells colored and raised by metric value (default)
'hexgrid-2d' Flat hexagonal cells colored by metric value
'square-3d' 3D extruded square cells colored and raised by metric value
'square-2d' Flat square cells colored by metric value
'heatmap' MapLibre density heatmap from tile center points

Switch modes at any time using setMode():

analyticsModule.setMode('heatmap');
analyticsModule.setMode('hexgrid-2d');
analyticsModule.setMode('square-3d');

Metrics

Five metrics are available to drive color and extrusion height. Set the active one via activeMetric. Per-metric style settings (color, height, filters) are configured via metricConfig.

Metric Description
'congestionLevel' Percentage increase in travel time above free-flow conditions (default active metric)
'speed' Average vehicle speed in km/h
'travelTime' Average travel time per 10 km in minutes
'freeFlowSpeed' Average speed under uncongested conditions in km/h
'networkLength' Total road length within each tile in metres — useful as a road density indicator
analyticsModule.setMetric('speed');
analyticsModule.setMetric('travelTime');
analyticsModule.setMetric('freeFlowSpeed');

You can also pre-configure multiple metrics at init time:

const analyticsModule = await TrafficAreaAnalyticsModule.get(map, {
    activeMetric: 'congestionLevel',
    metricConfig: {
        congestionLevel: { color: 'trafficLight' },
        speed: { color: 'heat' },
        travelTime: { height: { maxHeightMeters: 300 } },
    },
});

Color

Color configuration is per-metric and set under metric.[metricKey].color. You can use a preset theme name or provide custom color stops.

Preset Themes

// Apply a preset theme to all metrics
analyticsModule.setColor('trafficLight'); // green → amber → red (default)
analyticsModule.setColor('heat');         // blue → orange → red
analyticsModule.setColor('monochrome');   // light grey → dark grey
analyticsModule.setColor('viridis');      // purple → blue → green → yellow
analyticsModule.setColor('plasma');       // purple → magenta → orange → yellow

Custom Color Stops

Provide an AreaAnalyticsColorStopsConfig object with a valueType and stops array.

'raw' (default) — stop value fields are actual data values:

analyticsModule.setColor({
    valueType: 'raw',
    stops: [
        { value: 0,   color: '#2dc653' },  // 0% congestion
        { value: 30,  color: '#f5a623' },  // 30% congestion
        { value: 100, color: '#e03030' },  // 100% congestion
    ],
});

'relativeToPredefinedRangePCT' — stop value fields are 0–100 percentages relative to the SDK's predefined metric ranges (congestion 0–100, speed 0–120 km/h, travelTime 0–20 s/km). Useful for consistent coloring across datasets:

analyticsModule.setColor({
    valueType: 'relativeToPredefinedRangePCT',
    stops: [
        { value: 0,   color: '#2dc653' },  // 0% of predefined range
        { value: 50,  color: '#f5a623' },  // 50% of predefined range
        { value: 100, color: '#e03030' },  // 100% of predefined range
    ],
});

'relativeToActualRangePCT' — stop value fields are 0–100 percentages relative to the live data range actually present in the loaded tiles (0 % = loaded minimum, 100 % = loaded maximum). Maximises contrast regardless of absolute values:

analyticsModule.setColor({
    valueType: 'relativeToActualRangePCT',
    stops: [
        { value: 0,   color: '#2dc653' },  // 0% of loaded range
        { value: 50,  color: '#f5a623' },  // 50% of loaded range
        { value: 100, color: '#e03030' },  // 100% of loaded range
    ],
});

Pass undefined to revert to the default 'trafficLight' theme:

analyticsModule.setColor(undefined);

For speed, the color order is automatically inverted so that slow speeds render as "bad" (red) and fast speeds as "good" (green).

Height

Height (extrusion) configuration is per-metric under metric.[metricKey].height. Use setHeight() to update the active metric's height config.

// Predefined range (default): metric normalized to SDK predefined range, visual max = maxHeightMeters
analyticsModule.setHeight({ maxHeightMeters: 200 });

// Set a minimum height floor
analyticsModule.setHeight({ maxHeightMeters: 100, minHeightMeters: 10 });

// Current range: normalizes to live data range — maximises contrast for whatever data is loaded
analyticsModule.setHeight({ maxHeightMeters: 150, scaleMode: 'currentRange' });

// Raw: scaleFactor is multiplied directly with the raw metric value to obtain height in meters
analyticsModule.setHeight({ scaleMode: 'raw', scaleFactor: 10 });

Filtering

Filter visible tiles by value range for the active metric using filter(). Only tiles within the given range will be rendered.

// Show only tiles with congestion ≥ 50
analyticsModule.filter({ min: 50 });

// Show only tiles within a range
analyticsModule.filter({ min: 20, max: 80 });

// Clear the filter
analyticsModule.clearFilter();
analyticsModule.filter(undefined); // equivalent

Region Boundary

When show() is called, all region polygons in the analytics response are rendered alongside the analytics cells as a subtle fill with an outline. Customize their appearance using regionPolygon:

const analyticsModule = await TrafficAreaAnalyticsModule.get(map, {
    regionPolygon: {
        color: '#0052a5',      // fill and outline color (default: '#000000')
        fillOpacity: 0.08,     // default: 0
        outlineOpacity: 1.0,   // default: 0.5
        outlineWidth: 3,       // default: 2
    }
});

Layer Positioning

Control where analytics layers are placed in the map's rendering stack using beforeLayerConfig. Use 'top' to draw above all layers, or supply a well-known style layer ID to insert the analytics layers below it.

// Place below all labels (default behavior)
const analyticsModule = await TrafficAreaAnalyticsModule.get(map, {
    beforeLayerConfig: { heatmap: 'lowestLabel' },
});

// Place everything on top
const analyticsModule = await TrafficAreaAnalyticsModule.get(map, {
    beforeLayerConfig: {
        heatmap: 'top',
        hexgrid: { flat2D: 'top', extrusion3D: 'top' },
    },
});

// Reposition after initialization
analyticsModule.moveBeforeLayer({
    hexgrid: { flat2D: 'lowestLabel', extrusion3D: 'lowestPlaceLabel' },
});

Visibility

Control overall layer visibility:

// Hidden at startup
const analyticsModule = await TrafficAreaAnalyticsModule.get(map, { visible: false });

// Toggle later
analyticsModule.setVisible(true);

// Check current state
console.log(analyticsModule.isVisible()); // true | false

Events

Listen to click and hover events on hexgrid and square cells. Events fire for whichever mode is currently active.

analyticsModule.events.on('click', (feature, lngLat) => {
    console.log('Congestion:', feature.properties.congestionLevel);
    console.log('Speed:', feature.properties.speed);
});

analyticsModule.events.on('hover', (feature) => {
    console.log('Hovered cell:', feature.properties);
});

analyticsModule.events.on('long-hover', (feature) => {
    console.log('Long-hovered cell:', feature.properties);
});

// Remove a specific listener
analyticsModule.events.off('click');

Custom Tooltip on Hover

Use events.on('hover') to build a hover tooltip:

import { Popup } from 'maplibre-gl';

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

analyticsModule.events.on('hover', (feature, lngLat) => {
    if (!feature) { popup.remove(); return; }
    const { congestionLevel, speed } = feature.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());

Config Change Events

Subscribe to config changes emitted whenever a setter is called:

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

Querying Shown Features

Use getShown() to access the GeoJSON feature collections currently rendered for each visualization mode:

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

API Reference

For complete documentation of all properties, methods, and types, see the TrafficAreaAnalyticsModule API Reference.

Related Guides and Examples

Traffic Overview

Related Traffic Modules

Related Examples