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

Map styling

The Styling Foundations Module holds what every part of the map shares as semantic knobs. They cover label, icon and road sizes, the label typeface, the ten map colours and the accent, and a globe with a sky.

The playground below builds one control per knob from the catalogues of this module and the other style-owned ones.

Each feature built on the knobs has its own guide:

Guide Covers
Map colours and the accent setMapColors over the ten map colours, and the accent the modules' own drawing defaults to
Map typeface The labels.typeface knob, and your own font files for every label on the map
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);

Pass settings to apply them right away. The configuration nests each setting along its knob id, so labels.sizeFactor is labels: { sizeFactor }:

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

Knobs

Every adjustable thing is a knob with a stable id, the setting's path in the configuration. Set one with setKnob, several at once with setKnobs, read one with getKnob, and restore the style's own value with resetKnob, as on every module:

import { getKnob, resetKnob, setKnob, setKnobs, 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
setKnobs(styling, knobs, { 'colors.roadMajor': '#f59e0b', 'view.projection': 'globe' }); // one restyle

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

Use the knob functions for values held as data, from a control, storage or a language model, since they check each value against the catalogue. Use applyConfig and updateConfig for settings your code writes, typed. They don't check values at run time, and updateConfig({ colors: { water } }) replaces every colour you set before. Changing a setting compares the two.

How knobs work

setKnob · setKnobs · 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 value, so zoom ramps and the road hierarchy are kept. A zoom ramp has each stop's output scaled, and any other expression E becomes ["*", 1.3, E]
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, and the modules read it
toggle true / false view.sky.visible turns the sky on or off
enum one of the knob's options picks a mode, here the projection

Every knob also follows the same rules:

Every knob

Group Knobs Kind
Sizes labels.sizeFactor, symbols.sizeFactor, roads.widthFactor factor 0.5–1.5
Typeface labels.typeface (sans | sans-italic | serif | serif-italic) enum
Map colours colors.land, colors.water, colors.vegetation, colors.park, colors.artificial, colors.roadMajor, colors.road, colors.roadOutline, colors.label, colors.labelHalo, and colors.accent colour
View view.projection (mercator | globe) enum
view.sky.visible toggle
view.sky.color, view.sky.horizonColor, view.space.color colour

The module that shows a part holds its look, which you set with the same setKnob:

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, readable with no map loaded. Its entries share the shape of every module's catalogue (Every setting as data):

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

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

Every colour a knob sets on the loaded style, whichever module holds it, also has a map-wide id. It is the module's prefix followed by 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.colors.shaded). styleColorKnobIds lists them, typed StyleColorKnobId. getStyleColor reads the current colour of any of them (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'); // undefined where the style colours it by an expression

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.

When you wire controls to the catalogue, copy two things from the playground:

Presets

A map preset is a named bundle of knob settings for a common intent. It sets knobs across the modules that hold the look of the map, which are this one, 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 icons, wider roads, exit badges and road arrows shown, no POI dots, POIs from 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 a sky
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. For the visual half of the data-viz intent, dimming and desaturating what remains, pair it with the map effects plugin's grade and tint.

Exporting the style

exportStyle() returns the map's style as currently rendered, as a MapLibre style specification. This is the loaded style with every knob applied, plus whatever the SDK's data modules (places, routes) have added to it. Save it, diff it or serve it yourself.

Settings: persist, share, re-apply

getConfig() returns the overridden knobs as a plain object (StylingFoundationsModuleConfig), each nested along its id. applyConfig() replaces every knob with one, and updateConfig() replaces the top-level groups given, such as colors, and keeps the rest. It serializes cleanly, so styling can live in local storage, a URL or a pull request. It keeps working on a later SDK version 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));

applyConfig doesn't check what it reads back. If the settings come from somewhere you don't control, such as a shared URL, keep them as knob values by id and restore them with setKnobs, which refuses them all if one is out of range:

setKnobs(styling, stylingFoundationsKnobCatalogue, JSON.parse(new URLSearchParams(location.search).get('styling') ?? '{}'));

Style changes

The style (style on the map, or setStyle) decides which map document loads. Knobs adjust whichever one is loaded.

How durable is this?

There are two kinds of knobs, told apart by appliesTo in the catalogue:

Nobody re-tests a setPaintProperty against a layer id when the style changes version. A knob is re-verified on every style release the SDK ships.

Interplay with other modules

Who owns what states which module owns which layers. In short:

API reference

For complete documentation, see the StylingFoundationsModule API Reference.

Related guides and examples

Related guides

Related examples