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.
- It owns the fills, borders and labels it draws and how they look:
color,fill,line, the labels, the fill style and the palette. - It never restyles the base map, which belongs to the Styling Foundations module, and styling knobs never reach geometry layers: a geometry given no colour takes the map's accent. Who owns what draws the line for every module.
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 |
- The accent applies when a theme sets one.
- The default follows the map style: navy
#0A3653on light styles, sky blue#5FA8D8on dark ones. - With
fillStyle: 'outline', the border ends on a neutral grey,#555555, instead of the accent or 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' } }
}
});
- Where the layers sit stays
beforeLayerConfig's, so abeforeIDin an entry is ignored. - A layer an entry hides through
layout.visibilitystays hidden while the module is shown. updateConfig({ layers })repaints the geometries shown without preparing them again.
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:
- Unset, the fill opacity doubles, at most opaque, and the border width grows 1.75 times.
- The factors multiply the opacity and width in force, a
fill.opacityorline.widthyou set included. 1draws a hovered geometry as any other, which keeps its look fixed.- A width given through
layers.lineis drawn as given, in every state.
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:
- A part takes its own entry, else
all, else its default place just below the geometry titles. 'top'keeps the titles above everything else.updateConfig({ beforeLayerConfig })moves the layers by the same rules, so a part the new value names no target for goes back to its default place.
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).
- Both take a
title, a string or a MapLibre expression, the feature'stitlewhen unset. - Both take the styling fields every module's labels share:
size,color,haloColor,haloWidth,opacityandfont. lineLabeladdsminZoom,symbolSpacingandoffset.- Unset colours follow the map style: dark text on a white halo on light styles, the reverse on dark ones.
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.
- An empty list counts as unset; with no palette every feature draws in one colour, the map's accent or the default.
- Where
fill.palettesits among the colours is in the precedence table. - To match the map, take the palette from the colours the map is themed from: the
map-theme plugin's
deriveMapColorsreturns them by role.
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 |
- Opacities and widths have no
defaultentry where the fill style decides it, and colours none where the accent or the map style does. - Setting any
lineLabelknob draws the border labels. - A
fontknob's options aremapFonts,['Noto-Bold']unless set; order matters, since the first font the map has wins. lineLabel.offsetis in ems, x along the line and y across it,[0, 1]unless set.geometriesKnobIdslists the ids in catalogue order,GeometriesKnobIdis their union, andGeometriesKnobValueOf<ID>the plain value one takes.- Not in it:
beforeLayerConfig,layers, the labels'titleandtransformFeaturesForDisplay, which take structured, MapLibre or function values, andevents. - Its entries share their shape,
KnobEntry, with every module's catalogue.
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:
geometry— the polygons with the colours, fill styles and titles the config gave them, aninvertedone as the area outside it.geometryLabel— the points their center labels sit at.
const { geometry } = geometryModule.getShown();
console.log(`Geometries: ${geometry.features.length}`);
Related guides and examples
Services integration
- Geometry data service - Boundary and shape data for administrative areas and places
- Search services - Finding places and administrative areas that have geometry data
Related examples
- Basic geometry - Simple geometry display and styling
- Multiple geometries - Several geometry layers and data sets
- Multiple geometry modules - Several modules managed side by side
- Geometry config playground - Fill and border colours, layer-stack positions, visibility and the clicked look
- Places in geometry - Geometry boundaries combined with place markers
- Geometry search playground - Searching inside a geometry
Related map modules
- Reachable ranges module - Ranges calculated by budget, drawn as bands nested around their origins
- Places module - Places and POIs within or around geometric boundaries
- Routing module - Routes through geometric areas
- User interaction events - User interactions with geometric shapes and boundaries