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

Geometries module

GeometriesModule draws polygons on the map, each with a fill, a border and a label: administrative boundaries from the geometry data service, or any GeoJSON Polygon and MultiPolygon features of your own.

Showing geometries

Initializing geometry module

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

TomTomConfig.instance.put({ apiKey: 'YOUR_API_KEY' });
const map = new TomTomMap({ mapLibre: { container: 'map' } });

const geometryModule = await GeometriesModule.create(map);

Displaying administrative boundaries

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

const place = (await geocode({ query: 'Amsterdam, Netherlands' })).features[0];
const geometryResponse = await geometryData({ geometries: [place] });

await geometryModule.show(geometryResponse);

show replaces the geometries shown, and clear removes them.

Custom styling configuration

One top-level color sets the fill and the border together:

const geometryModule = await GeometriesModule.create(map, { color: '#E63312' });

The colours resolve in this order, first match wins:

Part Precedence
Fill a feature's own color property → fill.color → fill.palette → color → the map's accent → the default
Border line.color → a feature's own color property → fill.color → fill.palette → color → the map's accent → the default

fill and line configure the fill and the border apart: fill: { color, opacity }, or a palette instead of one colour, and line: { color, width, opacity }:

const geometryModule = await GeometriesModule.create(map, {
    fill: { color: '#007cbf', opacity: 0.3 },
    line: { color: '#005a8b', width: 2, opacity: 0.8 },
    beforeLayerConfig: 'lowestLabel' // below all the map's labels
});

For anything else, layers takes a partial MapLibre layer, without id or source, for each of the module's layers: fill, line (the border), label (the center labels) and lineLabel (the border labels). It can set any property of that layer, and its paint and layout merge per property onto the module's own, over the curated fields:

const geometryModule = await GeometriesModule.create(map, {
    line: { color: '#00A65E', width: 2 },
    layers: {
        line: {
            paint: {
                'line-offset': 2,          // inset/outset border, in pixels
                'line-blur': 4,            // glow, in pixels
                'line-dasharray': [2, 2],  // dash pattern in line-width units
                'line-gap-width': 3        // hollow casing
            },
            layout: { 'line-cap': 'round' }
        },
        label: { layout: { 'text-transform': 'uppercase' } }
    }
});

Restyling shown geometries

A config change reaches the geometries on the map — their colours, fill style, labels and transformFeaturesForDisplay — with no new show(). applyConfig replaces the whole config, updateConfig changes only what it is given, and resetConfig returns to the defaults:

await geometryModule.show(cityBoundaries);

geometryModule.updateConfig({ fill: { palette: ['#e63312', '#f5a000'] }, fillStyle: 'outline' });
geometryModule.updateConfig({ label: { title: ['get', 'name'] } }); // keeps the palette and fill style
geometryModule.resetConfig(); // default colours, fill style and labels

getConfig() returns the settings to store. All of it survives JSON but transformFeaturesForDisplay, a function, so GeometriesModuleSerializableConfig types what you parse back and a replay adds the function in code:

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

const saved: GeometriesModuleSerializableConfig = JSON.parse(JSON.stringify(geometryModule.getConfig()));
geometryModule.applyConfig({ ...saved, transformFeaturesForDisplay: addAreaLabels });

Hovered and clicked geometries

Once a handler covers the geometries, the one under the pointer draws a denser fill and a wider border in its own colour, and so does a clicked one. The module's event state methods put that state from your own UI:

geometryModule.events.on('click', (geometry) => console.log(geometry.properties.name));
geometryModule.setEventState({ id: 'amsterdam', state: 'click' });

highlight sets how much denser and wider, live on the geometry config playground:

geometryModule.applyConfig({
    fill: { opacity: 0.3 },
    highlight: { fill: { opacityFactor: 3 }, line: { widthFactor: 1 } }, // 0.9 while hovered, the border as is
});

Events

events covers the geometries and their center labels, and a handler receives the feature as drawn. Two named scopes single one surface out, with the same handlers and event states: events.geometry for the fills and borders, events.geometryLabel for the labels.

geometryModule.events.on('click', (geometry, lngLat) => console.log(geometry.properties.title, lngLat));
geometryModule.events.geometry.on('hover', (geometry) => showTooltip(geometry.properties.title));

The user events guide covers the event types and their timings.

Showing and hiding

setVisible hides and shows the fills, borders, center labels and border labels together, and visible: false at creation starts the module hidden. show() and clear() never change it: geometries shown while hidden appear on setVisible(true), and the state survives a style change.

function toggleGeometry() {
    geometryModule.setVisible(!geometryModule.isVisible());
}

Layer positioning and styling

A single beforeLayerConfig positions all geometry layers together. The record form { all?, fill?, line? } places the fill and the border apart:

const geometryModule = await GeometriesModule.create(map, {
    fill: { color: '#87CEEB', opacity: 0.5 },
    line: { color: '#4682B4', width: 1.5 },
    // Fill slips below the road network while the border stays above the labels
    beforeLayerConfig: { fill: 'lowestRoadLine', line: 'lowestLabel' }
});

Labels

Each polygon whose feature carries a title property gets a center label, which label styles. lineLabel repeats it along the border, drawn only when set ({} for the defaults).

const module = await GeometriesModule.create(map, {
    label: { title: ['get', 'name'], size: 18, color: '#FFFFFF', haloColor: '#000000' },
    lineLabel: { title: ['get', 'name'], minZoom: 10, size: 13, offset: [0, 1], symbolSpacing: 350 },
});

// Later: restyle the center labels of the shown geometries, keeping their other settings
module.updateConfig({ label: { ...module.getConfig()?.label, size: 20 } });

Deriving display properties

transformFeaturesForDisplay receives what show() was given and returns the features to draw, so a label or a colour can come from your own domain data. It runs on every show(), and again whenever a config change alters what is drawn:

const module = await GeometriesModule.create(map, {
    transformFeaturesForDisplay: (geometries) => ({
        ...geometries,
        features: geometries.features.map((feature) => ({
            ...feature,
            properties: { ...feature.properties, title: `${feature.properties?.name} (${feature.properties?.population})` },
        })),
    }),
});

Fill styles

Fill style Effect
'filled' Semi-transparent fill (default)
'outline' Transparent fill with a thick border
'inverted' Semi-transparent area outside the polygon

Setting the fill style at config level

fillStyle applies one fill style to every feature, and a feature's own fillStyle property overrides it:

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

// Highlight "rest of the world" outside a country
const module = await GeometriesModule.create(map, {
    fillStyle: 'inverted',
    fill: { color: 'black', opacity: 0.5 },
});
await module.show(countryGeometry);

Using fillStyledGeometryConfig for mixed fill styles

For features in one module with different fill styles, fillStyledGeometryConfig({ palette?, beforeLayerConfig? }) returns a config whose expressions read each feature's fillStyle property. beforeLayerConfig defaults to 'lowestLabel'.

import { GeometriesModule, fillStyledGeometryConfig } from '@tomtom-org/maps-sdk/map';

const module = await GeometriesModule.create(map, fillStyledGeometryConfig({ palette: ['#0077b6', '#90e0ef'] }));

await module.show({
    type: 'FeatureCollection',
    features: [
        { ...featureA, properties: { fillStyle: 'filled', title: 'Zone A' } },
        { ...featureB, properties: { fillStyle: 'outline', title: 'Zone B' } },
    ],
});

Color palettes

fill.palette is a list of CSS colours the features take in turn, starting over after the last, so neighbouring polygons stay apart without a colour assigned to each.

import { fillStyledGeometryConfig, GeometriesModule } from '@tomtom-org/maps-sdk/map';
import { deriveMapColors } from '@tomtom-org/maps-sdk-plugin-map-theme';

const regions = await GeometriesModule.create(map, {
    fill: { palette: ['#ffadad', '#ffd6a5', '#caffbf', '#a0c4ff'], opacity: 0.3 },
});

// fillStyledGeometryConfig takes it as its `palette` option
const { accent, water, roadMajor } = deriveMapColors(['#1d3f8a', '#e63312', '#f5d000', '#f4f1ea']);
const zones = await GeometriesModule.create(map, fillStyledGeometryConfig({ palette: [accent, water, roadMajor] }));

Reachable ranges have a module of their own, the reachable ranges module, which titles each band from its budget, nests each origin's bands and colours them from the map.

Every setting as data

geometriesKnobCatalogue lists every plain-valued display setting of the module with its kind, its range or options and, where one value holds everywhere, its default. Each id is the setting's path in the config, so a UI can build its controls from it with no map loaded:

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

const borderKnobs = geometriesKnobCatalogue.filter(({ id }) => id.startsWith('line.'));
// [{ id: 'line.color', kind: 'color', description: '…' }, …,
//  { id: 'line.width', kind: 'number', description: '…', range: { min: 0, max: 20, step: 0.5, bounds: 'hard-min' } }]
Id Kind
color, visible, fillStyle colour, toggle, enum
fill.color, fill.palette, fill.opacity colour, colours, number
line.color, line.opacity, line.width colour, number, number
highlight.fill.opacityFactor, highlight.line.widthFactor factor, 1 to 4 and 1 to 3
label.size, label.color, label.haloColor, label.haloWidth, label.opacity, label.font number, colour, colour, number, number, enums
lineLabel.size, lineLabel.color, lineLabel.haloColor, lineLabel.haloWidth, lineLabel.opacity, lineLabel.font, lineLabel.minZoom, lineLabel.symbolSpacing, lineLabel.offset the label knobs, then number, number, offset

Multiple module instances

Each instance has its own sources, layers and configuration, so several can show different sets of geometries side by side:

const countryBorders = await GeometriesModule.create(map, {
    fill: { color: '#E74C3C', opacity: 0.2 },
    line: { color: '#C0392B', width: 3 }
});

const cityBounds = await GeometriesModule.create(map, {
    fill: { color: '#3498DB', opacity: 0.3 },
    line: { color: '#2980B9', width: 2 }
});

await countryBorders.show(countryData);
await cityBounds.show(cityData);

Reading shown data

getShown() returns what the module draws, as prepared for display:

const { geometry } = geometryModule.getShown();
console.log(`Geometries: ${geometry.features.length}`);

Related guides and examples

Services integration

Related examples

Related map modules