Skip to main content

POIs & Content Search

WemapMap handles interaction and state for pinpoints already rendered in the livemap style (vector-tile / GeoJSON features carrying a pinpoint property). This is distinct from DomMarkerLayer, which places your own runtime DOM pins.

POI interaction is owned by the map and is torn down with map.remove().

Clicks

onPoiClick resolves the full Pinpoint entity for the clicked feature. When the pinpoint can't be resolved, no click event is fired and onPoiClickError is notified instead.

map.onPoiClick(({ pinpoint, externalId, coordinates }) => {
console.log('clicked', pinpoint.id, pinpoint.name, externalId, coordinates.lat, coordinates.lng);
});

map.onPoiClickError(({ pinpointId, reason }) => {
console.warn('POI resolution failed', pinpointId, reason);
});

Highlight, select, filter

map.setPoiHighlighted([12, 34]);
map.setPoiSelected([56]);

map.filterPois([12, 34, 56]); // whitelist on default layers
map.showAllPois(); // clear the filter — show all again
map.hideAllPois(); // hide all pinpoints on default layers

filterPois([]) is equivalent to hideAllPois(). getPoiFilter() returns the current whitelist (null = no filter, [] = all hidden), and getPoiHighlighted() / getPoiSelected() read the current lists. All three states are re-applied automatically across a style swap.

Highlighted, selected, and filtered are independent states — a selected POI and a set of highlighted search results coexist without interfering.

Automatic userflow

The calls above are the building blocks. To get the standard userflow without wiring it yourself, opt in with the interaction option — every toggle is off by default:

const map = new WemapMap({
container: 'map',
interaction: {
autoSelectOnClick: true, // click a POI → select it; click empty → clear
autoHighlightSearch: true, // map.search() highlights results + filters others
// centerOnSelect: true // (default) also ease the camera to the selected POI
},
});
  • autoSelectOnClick — clicking a stylesheet POI selects it (replacing any previous selection) and, unless centerOnSelect: false, eases the camera to it. Clicking the empty map background clears the selection. Your own onPoiClick listeners still fire on top of this.
  • autoHighlightSearch — makes map.search() apply its results to the map (highlight + filter) instead of only returning them.

You can always mix the auto-flow with the manual setPoiSelected / setPoiHighlighted / filterPois calls.

Viewport pinpoints

To react to the pinpoints currently in view (for a synchronized list, say), subscribe to viewport changes. The callback fires on load, after the map stops moving, and on level change:

map.onViewportPinpointsChange(({ pinpoints, trigger }) => {
console.log('refreshed via', trigger, pinpoints.length);
});

map.search(query) searches the livemap's pinpoints within the current viewport and level — no need to assemble the bounds/level query yourself:

const map = new WemapMap({
container: 'map',
interaction: { autoHighlightSearch: true },
});

const { items } = await map.search('museum');
// with autoHighlightSearch on: results are highlighted and every other
// pinpoint is filtered out of the default layers, in this one call.

map.clearSearch(); // clear the highlight + show all again (selection is kept)

Pass overrides via the second argument: map.search('museum', { limit: 20, tags, level }). When interaction.autoHighlightSearch is off, map.search() just returns the results and leaves the map untouched — apply them yourself with filterPois / setPoiHighlighted if you want.

For a custom search backend, skip map.search() and drive the primitives directly — @wemap/core exposes the lower-level pinpointManager.search:

import { boundsToDelta, core } from '@wemap/core';

const pinpointManager = core.createPinpointManager();
const { items } = await pinpointManager.search({
query: 'museum',
...boundsToDelta(map.getBounds()),
level: map.getLevel() ?? undefined,
});

map.setPoiHighlighted(items.map((p) => p.id));
map.filterPois(items.map((p) => p.id));

For the full API, see the Map API reference.