Skip to main content

Markers & Clustering

DomMarkerLayer places runtime DOM pins (destinations, annotations, waypoints) on the map. It is separate from stylesheet POIs and from UserLocationLayer. You can also use it if your map doesn't have any POIs and you want to add them dynamically.

import { Coordinates } from '@wemap/geo';
import { DomMarkerLayer } from '@wemap/map';

const markers = new DomMarkerLayer(map, { levelVisibility: true });
markers.add({ id: 'dest', position: new Coordinates(48.85, 2.35, null, 1) });
markers.remove('dest');

add upserts by id (call it again with the same id to move / restyle a marker). position accepts any LatLngLike — a Coordinates, a { lat, lng, level? } object, or a [lat, lng, level?] tuple — and an invalid position throws. Pass a color / icon for the default pin, or your own element for a fully custom marker. Individual marker clicks:

markers.on('click', ({ id, position }) => console.log('clicked', id, position));

Level visibility

By default (levelVisibility: true), a marker is hidden when its position.level does not match map.getLevel(). When map.getLevel() is null (outdoor / no floor selected), all markers stay visible. Pass levelVisibility: false to always show every marker.

Clustering

Opt-in supercluster grouping, per layer. Omit cluster for 1:1 markers (the default). Use a second, non-clustered DomMarkerLayer for pins that must never cluster (origin, destination, …):

const pois = new DomMarkerLayer(map, {
cluster: {
enable: true,
radius: 80, // optional — livemap default
maxZoom: 18, // optional — defaults to the map's max zoom
zoomOnClick: true,
color: '#c0392b', // optional — overrides the themed default (--wemap-color-cluster)
},
});

pois.on('clusterclick', (event) => {
console.log(event.pointCount, event.markerIds);
// event.preventDefault(); // skip the default expansion zoom
});

pois.setClusterEnabled(false); // runtime toggle (no-op without constructor cluster config)

Cluster clicks zoom to the supercluster expansion level by default; individual marker on('click') is unchanged. When levelVisibility is true, markers hidden for the current floor don't participate in clustering, so clusters never span floors.

Clean up

DomMarkerLayer is not destroyed by map.remove() by default — call markers.destroy(), or cascade with map.remove({ layers: true }).

For the full API, see the DomMarkerLayer reference.