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

Map styling

The Styling Foundations Module restyles what every part of the map shares through semantic knobs: bigger labels and icons, thicker roads, the ten map colours, a globe with a sky. It sits between showing and hiding what the style draws with the other style-owned modules and editing individual MapLibre layers by hand — and unlike either, it is designed to be read by machines: the whole catalogue of knobs is available as data.

The look of a part another module shows is that module's own knobs, set the same way: POI size and label colours on POIsModule, the traffic colours on the traffic flow and traffic incidents modules, the shading on TerrainModule, the road markings on BaseMapModule. The playground below is built from those catalogues: one control per knob.

This guide covers the knobs themselves. The features built on them each have a guide of their own:

Guide Covers
Map colours and the accent setMapColors over the ten map colours, and the accent the modules' own drawing defaults to
Globe and sky The view knobs: globe projection, sky, horizon and the colour behind the map
Borrowed looks The parts of places, routes and fetched incidents that follow the style's own looks
Editing style layers styling.layers, for what no knob covers

Initialization

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

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

The module is shared per map: a second get() returns the same instance. Pass settings to apply them right away, for instance restored from storage:

const styling = await StylingFoundationsModule.get(map, { 'labels.sizeFactor': 1.2, 'colors.water': '#0fa8c8' });

get resolves once the style has loaded, before the map draws it. Knobs set before that first frame, whether passed to get or set right after it, land on it as if the style had shipped them, instead of fading in from the style's own look. So a map themed at startup never shows the default colours (Themed map).

Knobs

Every adjustable thing is a knob with a stable id. Set one with setKnob, read it with getKnob, restore the style's own value with resetKnob — the same three functions as on every module:

import { getKnob, resetKnob, setKnob, stylingFoundationsKnobCatalogue } from '@tomtom-org/maps-sdk/map';

const knobs = stylingFoundationsKnobCatalogue;
setKnob(styling, knobs, 'labels.sizeFactor', 1.3);    // every base-map label 30% bigger
setKnob(styling, knobs, 'roads.widthFactor', 0.8);    // thinner roads, hierarchy kept
setKnob(styling, knobs, 'colors.roadMajor', '#f59e0b');
setKnob(styling, knobs, 'view.projection', 'globe');

getKnob(styling, knobs, 'roads.widthFactor');   // 0.8
resetKnob(styling, knobs, 'roads.widthFactor'); // back to the style's width
styling.resetConfig();                          // everything back to the style as shipped

How knobs work

A knob's kind decides what it does to the loaded MapLibre style. Most write the style's layers; a few go elsewhere: the view knobs to the map itself, and colors.accent to no layer at all, for the modules that draw their own layers to read. Showing or hiding a whole layer group (water, 3D buildings, road shields) is no knob of this module: that is the Base Map Module's.

The look knobs of the POIs, traffic and terrain modules restyle the same loaded style through one shared engine per map. So knobs that reach one layer property compose, whichever module set them — labels.sizeFactor here and sizeFactor on POIsModule multiply on the POI labels — and all of them land on top after a style switch.

setKnob · applyMapPreset · setMapColors · applyConfigmap.setStyle(…)StylingFoundationsModule: the knobs you set, by kindPOIsModule · TrafficFlowModuleTrafficIncidentsModule · TerrainModuletheir look knobs: size · zoom · colours · widthmap.mapColors.accentread by routes, places,geometries and rangesMapLibre mapfactorwraps the style's own expressiona style expression E becomes 1.3 × Ecolourthe colour, and every shadethe style derived from itview.*projection · sky · space colourcolors.accentpaints no layerThe loaded style's layerspaint · layout · filters · visibilityMap viewprojection · sky · background re-applied last, after every switchsame engine:factors multiply with the ones here
Kind Takes What it does
factor a multiplier, 1 = as the style ships multiplies the style's own expression — text-size: E becomes ["*", 1.3, E] — so zoom ramps and the road hierarchy are kept
colour any CSS colour replaces the colour, and re-derives the shades the style built from it: recolouring the major roads recolours their darker outline by the same offset. colors.accent paints no layer: the modules read it
toggle true / false view.sky turns the sky on or off
enum one of the knob's options picks a mode: the projection

Every knob also follows the same rules:

Knobs write only the style's layers and the map's view. What the SDK draws itself — routes, places, geometries — is configured on its own module, and a few of its parts follow the knobs (The accent, Borrowed looks).

Every knob

Group Knobs Kind
Sizes labels.sizeFactor, symbols.sizeFactor, roads.widthFactor factor 0.5–1.5
Map colours colors.land, colors.water, colors.vegetation, colors.park, colors.artificial, colors.roadMajor, colors.road, colors.roadOutline, colors.label, colors.labelOutline, and colors.accent colour
View view.projection (mercator | globe) enum
view.sky toggle
view.skyColor, view.horizonColor, view.spaceColor colour

The sizes reach every base-map label, icon or road line, the POIs' and the road shields' included, and the map colours theme the whole map from one entry point. The look of one part is held by the module that shows it:

Part Module Its look knobs
Road markings BaseMapModule the exit numbers, arrows, restricted and under-construction roads, each shown or hidden
POIs POIsModule size, the zoom they appear at, zoom shift, label colours, micro markers
Traffic flow TrafficFlowModule the colour of each flow level, the line width
Traffic incidents TrafficIncidentsModule the colour of each severity, the line width
Hillshade TerrainModule method, light direction, strength, zoom range and colours

The knob catalogue

stylingFoundationsKnobCatalogue lists every knob as static data — id, kind, description, range or options, and which styles it works on — so it reads the same with no map loaded as with one. getKnob(styling, stylingFoundationsKnobCatalogue, id) gives the value in force on a live map.

import { getKnob, stylingFoundationsKnobCatalogue } from '@tomtom-org/maps-sdk/map';

for (const knob of stylingFoundationsKnobCatalogue) {
    // knob.id, knob.kind ('factor' | 'number' | 'toggle' | 'color' | 'enum'), knob.description,
    // knob.range (factor and number), knob.options (enum), knob.appliesTo
    const current = getKnob(styling, stylingFoundationsKnobCatalogue, knob.id);
}

The playground at the top of this guide is exactly that: its panel is generated from this catalogue and the look knobs of the other modules', each control showing the value getKnob reads. Its entries carry no default, since the loaded style decides; the other catalogues of the SDK share their shape (Every setting as data).

The ids are also exported on their own: stylingFoundationsKnobIds lists every knob, typed StylingFoundationsKnobId.

Every colour a knob sets on the loaded style, whichever module holds it, also has a map-wide id: the module's prefix, then its id in that module's catalogue. The Styling knobs keep their own ids (colors.water); the others take pois., traffic.flow., traffic.incidents. or terrain. (pois.label.color, traffic.flow.colors.slow, terrain.hillshade.shadowColor). styleColorKnobIds lists them, typed StyleColorKnobId, and getStyleColor reads the colour one is at — the one set, one the style derives from the map colours, or the style's own — whether or not its module exists:

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

getStyleColor(map, 'colors.water');
getStyleColor(map, 'traffic.incidents.colors.major');

Name a map colour through them rather than hard-coding it, as the map effects plugin does to scope its bloom. StyleKnobId and StyleKnobValueOf<ID> type every style knob by its map-wide id.

Two things are worth copying from the playground when you wire controls up. A slider or a colour picker fires input far faster than a restyle runs, so coalesce the calls into one setKnob per animation frame (last value wins) and apply the final value on change; the readout can follow every event, since updating a label costs nothing. And if you rebuild the panel from the config-change event, skip the rebuild for changes your own controls made — setKnob emits the event, so rebuilding mid-drag replaces the input under the pointer. Rebuild on external changes only: a reset, a setStyle, or an agent.

Presets

A map preset is a named bundle of knob settings for a common intent — TomTom's cartographic opinions, in code. It sets knobs across the modules that hold the look of the map: the Styling Foundations module, BaseMapModule's road parts and POIsModule's look. mapPresetCatalogue lists them with the settings each one applies, per module, by that module's catalogue ids (MapPresetSettings):

Preset Intent
data-viz A quiet base for your own data on top: smaller labels and icons, thinner roads, no exit badges or road arrows, no POI dots, POIs from zoom 14
night-driving Bigger labels and shields, wider roads, exit badges and road arrows shown, POIs out of the way until zoom 13
minimal The bare map: smaller labels, no road markings or exit badges, no POI dots, POIs from zoom 16
globe Globe projection with an atmosphere
import { applyMapPreset, setKnob, stylingFoundationsKnobCatalogue } from '@tomtom-org/maps-sdk/map';

await applyMapPreset(map, 'data-viz');                            // replaces what the other presets set
setKnob(styling, stylingFoundationsKnobCatalogue, 'labels.sizeFactor', 1.1); // then adjust
await applyMapPreset(map, 'globe', { merge: true });              // lay a preset over what is there

A preset is exactly as durable as the knobs it sets, and re-applying one on a later SDK version keeps working for as long as those knob ids do. For the visual half of the data-viz intent — dimming and desaturating what remains — see the map effects plugin's grade and tint.

Exporting the style

exportStyle() returns the map's style as currently rendered — the loaded style with every knob applied — as a MapLibre style specification. Save it, diff it, serve it yourself, or load it back as a custom style. Tile URLs carry the API key the map was created with; strip or rotate it before publishing the file.

Settings: persist, share, re-apply

getConfig() returns the overridden knobs as a plain object; applyConfig() takes one back. It serializes cleanly, so styling can live in local storage, a URL or a pull request, and re-applying it on a later SDK version keeps working for as long as the knob ids do:

localStorage.setItem('map-styling', JSON.stringify(styling.getConfig()));
// …later
styling.applyConfig(JSON.parse(localStorage.getItem('map-styling')));

styling.events.on('config-change', (settings) => save(settings));

Style changes

The style (style on the map, or setStyle) is which map document loads; knobs adjust whichever one is loaded. Settings survive map.setStyle(...): the module re-applies them once the new style has loaded, after the other modules have restored themselves, so knobs always land on top, on the new style's first frame. A clean switch (resetState: true) drops them along with the rest of the SDK state. See Map styles.

How durable is this?

Two kinds of knobs, told apart by appliesTo in the catalogue:

That is the contract: one call the SDK re-verifies on every style release, instead of a setPaintProperty block against layer ids that nobody tests again. Which style version the SDK verified against is our business, not yours — appliesTo tells you which knobs depend on it.

Interplay with other modules

The map modules split along who owns the layers — the rule is stated once, in Who owns what. In short:

The foundations live in one module because they reach across style parts — labels.sizeFactor, or a map colour that reaches land, water, roads and labels at once. Where a foundation and a part's own knob reach the same layer they compose, and a map preset sets both at once. A whole layer group has no styling knob: show or hide it with BaseMapModule.

API reference

For complete documentation see the StylingFoundationsModule API Reference.

Related guides and examples

Related guides

Related examples