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

Place styling

The Places module draws its places in a look of its own: the marker type, colour, icon and label settings below, each plain-valued one a knob in placesKnobCatalogue. Two things from outside reach these layers: the map's accent, for markers given no colour, and the knobs that restyle the style's POIs, for the marker types that borrow their look.

Marker type

markerType sets the kind of marker every place is drawn with, at creation or at runtime:

const placesModule = await PlacesModule.create(map, { markerType: 'base-map' });
placesModule.updateConfig({ markerType: 'circle-icon' });

// Micro dots only: `base-map` with a hidden `main` layer
const microPlaces = await PlacesModule.create(map, {
    markerType: 'base-map',
    layers: { main: { layout: { visibility: 'none' } } },
});

base-map, circle-icon and pin-clustered borrow the look of the style's POIs, so the knobs that restyle those POIs restyle them too; Borrowed looks lists which per marker type.

Clusters

Under the pin-clustered marker type, cluster sets how places cluster and how the count badge looks; every other marker type ignores it. badge styles the badge of single-category and mixed-category clusters together, and source takes MapLibre's cluster options:

const placesModule = await PlacesModule.create(map, {
    markerType: 'pin-clustered',
    // The per-place value the cluster aggregates
    extraFeatureProps: {
        connectorCount: (place) =>
            place.properties.chargingPark?.connectors.reduce((total, { count }) => total + count, 0) ?? 0,
    },
    cluster: {
        badge: { color: '#3f9cd9', radius: { single: 13, mixed: 18 } },
        source: {
            clusterRadius: 100, // default 60
            clusterMaxZoom: 14, // default 17
            // Total charging points across each cluster
            clusterProperties: { connectors: ['+', ['get', 'connectorCount']] },
        },
    },
    // An aggregated value lands on the cluster feature's properties
    layers: { clusterCount: { layout: { 'text-field': ['get', 'connectors'] } } },
});

Colour

color is the colour of the module's own drawing: the default pin fill, the label of a hovered or clicked place, connection lines and entry points. Connection labels take a darker shade of it on a light map and a lighter one on a dark map; entry points take the darker one on a light map.

const placesModule = await PlacesModule.create(map, { color: '#2A9D8F' });

Label styling

label sets the content and look of the labels next to the markers:

import { PlacesModule, type PlaceLabelConfig } from '@tomtom-org/maps-sdk/map';

// POI names red, other places blue
const label: PlaceLabelConfig = {
    title: (place) => place.properties.poi?.name ?? place.properties.address.freeformAddress,
    color: ['match', ['get', 'type'], 'POI', '#D32F2F', '#1976D2'],
    haloWidth: 2,
};
const placesModule = await PlacesModule.create(map, { label });

// `label` replaces the whole label: spread the current one to change a single field
placesModule.updateConfig({ label: { ...placesModule.getConfig()?.label, opacity: 0.8 } });

Icon styling

icon.categoryIcons draws the places of a category with an image of your own, under every marker type; places in other categories keep the marker type's icon.

import { PlacesModule, type PlaceIconConfig } from '@tomtom-org/maps-sdk/map';

const icon: PlaceIconConfig = {
    categoryIcons: [
        { id: 'RESTAURANT', image: '/icons/food.png', pixelRatio: 2 },
        // A pin whose tip sits 10 pixels below its centre
        { id: 'HOTEL_OR_MOTEL', image: '/icons/hotel.png', pixelRatio: 2, offsetY: -10 },
    ],
};
const placesModule = await PlacesModule.create(map, { markerType: 'pin', icon });

Extra properties

extraFeatureProps adds properties to every place feature, for layers expressions to read with ['get', '<name>'] and for event handlers:

placesModule.updateConfig({
    extraFeatureProps: {
        firstCategory: (place) => place.properties.poi?.categories?.[0],
        brand: (place) => place.properties.poi?.brands?.[0] ?? '',
        source: 'search',
    },
});

An entry is a fixed JSON value or a callback that receives a Place and returns one. When the places you show carry a narrower shape, such as EV charging stations with availability, name it on the config, or as the type parameter of applyConfig / updateConfig, and the callbacks are typed for it, along with label.title and icon.mapping:

import type { EVChargingStationWithAvailabilityPlaceProps } from '@tomtom-org/maps-sdk/core';
import type { PlacesModuleConfig } from '@tomtom-org/maps-sdk/map';

const config: PlacesModuleConfig<EVChargingStationWithAvailabilityPlaceProps> = {
    extraFeatureProps: {
        availableShare: (place) => {
            const { count, statusCounts } = place.properties.chargingPark.availability.chargingPointAvailability;
            return count ? (statusCounts.Available ?? 0) / count : 0;
        },
    },
};

Layer positioning

By default the markers sit above the map's layers, and the connection lines below its labels. beforeLayerConfig (PlacesBeforeLayerConfig) moves them: one target for everything the module draws, 'top' or a key of mapStyleLayerIDs, or a record keyed by part, plus all for the parts it leaves out. The parts are named after the event scopes:

// The markers under the map's labels; the connections stay where they are
placesModule.updateConfig({ beforeLayerConfig: { places: 'lowestLabel' } });

Every setting as data

placesKnobCatalogue 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, and the catalogue reads with no map loaded, so a UI can build its controls from it:

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

const badgeKnobs = placesKnobCatalogue.filter(({ id }) => id.startsWith('cluster.badge.'));
// [{ id: 'cluster.badge.color', kind: 'color', description: '…', default: '#000000' }, …,
//  { id: 'cluster.badge.radius.single', kind: 'number', description: '…', range: { min: 4, max: 32, step: 1, bounds: 'hard-min' }, default: 11 }, …]
Knob Kind Default
markerType enum 'pin'
color color the map's accent
visible toggle true
icon.default.style.fillColor color color
icon.default.style.outlineColor color
icon.default.style.outlineOpacity number
label.size number 14 to 16 pixels by zoom
label.color color by the map's light/dark theme
label.haloColor color by the map's light/dark theme
label.haloWidth number 1 to 1.5 pixels by zoom
label.opacity number
label.offset number from the icon's size
label.font enums Noto-Bold, or the style's under base-map
cluster.badge.color color '#000000'
cluster.badge.outlineColor color '#FFFFFF'
cluster.badge.outlineWidth number 1.5
cluster.badge.label.color color '#FFFFFF'
cluster.badge.label.size number 12
cluster.badge.radius.single number 11
cluster.badge.radius.mixed number 15
cluster.badge.offset offset [12, -14]
cluster.source.clusterRadius number 60
cluster.source.clusterMaxZoom number 17
cluster.source.clusterMinPoints number MapLibre's, 2
evAvailability.visible toggle false
evAvailability.threshold number 0.3
entryPoints.showFor enum 'selected'
entryPoints.minZoom number 15
connections.color color the module's color, else the map's accent, else by the map's light/dark theme
connections.label.color color a shade of the line's colour for the map's light/dark theme
connections.label.haloColor color by the map's light/dark theme

Related guides and examples

Related guides

Related examples