Place Interaction and Polygon Styling

Places are the core data model behind indoor maps. This example covers searching, selecting, and visually highlighting places on the map — the foundation for any directory or wayfinding UI.
It uses these place-centric APIs:
getInstitutionsgetPlacesByInputsearchPlacesByTagsgetPlaceDetailstartClickListenersetPlacesAsSelectedaddBorderToPlaces
Setup
import { initializeSDK } from "@mapvx/web-js"
const sdk = initializeSDK("<YOUR_API_KEY>", { lang: "es" })
const map = sdk.createMap(document.getElementById("map") as HTMLElement, {
center: { lat: 4.666918, lng: -74.053065 },
zoom: 17,
onMapReady: () => {
console.log("Ready for place interactions")
},
})Fetch institutions
Use institutions when search results should be scoped to a specific client or campus.
const institutions = await sdk.getInstitutions()
const institution = institutions[0]Search places by user input
const results = await sdk.getPlacesByInput(
"coffee",
institution.mapvxId,
"<OPTIONAL_PARENT_PLACE_ID>"
)
results.forEach((place) => {
console.log(place.mapvxId, place.title)
})To bias results with a coordinate and floor:
const nearbyResults = await sdk.getPlacesByInput(
"restroom",
institution.mapvxId,
"<PARENT_PLACE_ID>",
[],
"search-panel",
"4.666918",
"-74.053065",
"<FLOOR_ID>"
)Search places by tags
searchPlacesByTags matches places against one or more
tags (combined with OR semantics on the server) instead of free text. It’s the right fit for
category filters — e.g. “show every place tagged coffee or restaurant”.
const tagResults = await sdk.searchPlacesByTags(institution.mapvxId, ["coffee", "restaurant"])Sort the results alphabetically instead of by relevance:
const alphabetical = await sdk.searchPlacesByTags(institution.mapvxId, ["restroom"], {
sort: "alphabetical",
})To sort by distance, provide either a reference origin place id or the combination of lat +
lng + floor + parentPlaces — searchPlacesByTags throws if neither is present:
// From a known reference place (e.g. a totem)
const nearestFromTotem = await sdk.searchPlacesByTags(institution.mapvxId, ["restroom"], {
sort: "distance",
origin: "<TOTEM_PLACE_ID>",
})
// From an explicit coordinate + floor
const nearestFromCoordinate = await sdk.searchPlacesByTags(institution.mapvxId, ["restroom"], {
sort: "distance",
lat: "4.666918",
lng: "-74.053065",
floor: "<FLOOR_ID>",
parentPlaces: ["<PARENT_PLACE_ID>"],
})Highlight polygons

map.setPlacesAsSelected(["<PLACE_ID>"])
map.setPlacesAsSelected(["<PLACE_A>", "<PLACE_B>"], "#0F766E")Clear the color layer when needed:
map.clearColoredPlaces()Add borders to the same polygons

map.addBorderToPlaces(["<PLACE_ID>"])
map.addBorderToPlaces(["<PLACE_A>", "<PLACE_B>"], "#134E4A", 2)Clear borders independently:
map.clearBorderedPlaces()Click real places on the map


The click listener returns the MapVX ID of the clicked polygon on the active floor.
map.startClickListener(async (placeId: string) => {
const place = await sdk.getPlaceDetail(placeId)
map.setPlacesAsSelected([placeId], "#C2410C")
map.addBorderToPlaces([placeId], "#7C2D12", 2)
console.log("Clicked place", {
id: place.mapvxId,
title: place.title,
floor: place.inFloors?.[0] ?? "outdoor",
})
})Stop listening when the flow ends:
map.stopClickListener()Indoor and outdoor behavior
Indoor
- prefer
parentPlaceIdincreateMap - use
place.inFloors?.[0]to understand the visible floor - combine search, polygon styling, and floor changes
Outdoor
- no
parentPlaceIdis required getCurrentFloor()stays empty- polygon clicks and
isInsideBoundsstill work as expected
Combined search and highlight flow

async function searchAndHighlight(query: string): Promise<void> {
const results = await sdk.getPlacesByInput(query, institution.mapvxId)
if (results.length === 0) {
map.clearColoredPlaces()
map.clearBorderedPlaces()
return
}
// Limit visible results to avoid visual clutter
const topResults = results.slice(0, 5)
const ids = topResults.map((place) => place.mapvxId)
map.setPlacesAsSelected(ids, "#0F766E")
map.addBorderToPlaces(ids, "#134E4A", 2)
// Fit the map to show all highlighted places
const coords = topResults.filter((p) => p.position).map((p) => p.position)
if (coords.length > 0) {
map.fitCoordinates(coords, {
padding: { top: 60, right: 60, bottom: 100, left: 60 },
maxZoom: 19,
})
}
}If the next step in the user flow is to drop markers or build a route from the selected place, use Places, Markers, and Routes.