Skip to Content
ExamplesMap Controls and Bounds

Map Controls and Bounds

Map with viewport controls, bounds, and zoom configuration

Map controls demo: zoom, camera, bearing, and fitCoordinates

This guide covers the APIs that shape the current viewport and map state after creation.

Setup

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, showCompass: true, showZoom: true, navigationPosition: "top-right", onMapReady: () => { console.log("Map ready") }, onZoomEnd: (zoomLevel) => { console.log("Zoom changed", zoomLevel) }, onRotate: (degrees) => { console.log("Map bearing", degrees) }, })

Fit several coordinates

map.fitCoordinates( [ { lat: 4.666918, lng: -74.053065 }, { lat: 4.66715, lng: -74.0528 }, { lat: 4.6665, lng: -74.0535 }, ], { padding: { top: 80, right: 40, bottom: 120, left: 40, }, maxZoom: 18, onComplete: () => { console.log("Fit completed") }, } )

Fit coordinates under a bearing

fitCoordinates always fits a north-up rectangle, so a rotated or diagonal set of coordinates (e.g. a route drawn under a bearing) ends up framed with extra empty viewport. easeToCoordinates fits the same list of coordinates but computes an oriented bounding box aligned to the target bearing, so the frame stays tight. It accepts the same options as fitCoordinates; only the camera-change strategy differs (easeTo instead of fitBounds).

map.easeToCoordinates(routeCoordinates, { bearing: 140, padding: { top: 40, right: 40, bottom: 200, left: 40 }, duration: 800, })

Because the fitted frame is tighter than fitCoordinates, make sure the padding leaves enough room for any overlaid UI (instruction panels, buttons) so markers or route lines aren’t hidden behind it.

Update the camera explicitly

Camera demo: zoom, bearing, and pitch controls

map.updateCamera( { center: { lat: 4.667, lng: -74.0529 }, zoom: 18.5, pitch: 45, bearing: 20, duration: 1500, }, () => { console.log("Camera animation finished") } )

Set zoom limits

map.setMinZoom(15) map.setMaxZoom(20)

Lock the map orientation (totems / kiosks)

For fixed installations such as a totem or kiosk, the map should usually face a constant direction so that “up” on screen matches “forward” for the person standing in front of it. Set an initial bearing and disable user rotation with rotateEnabled: false — pinch‑to‑zoom keeps working, only rotation is locked.

const map = sdk.createMap(container, { center: { lat: 4.666918, lng: -74.053065 }, zoom: 19, bearing: 135, // degrees clockwise from north — align "up" with the totem rotateEnabled: false, // disable drag/touch/keyboard rotation, keep zoom })

You can also change the orientation at runtime — for example after the visitor picks which totem they are standing at — and toggle rotation on or off without re‑creating the map:

// Snap to a new orientation (use { animate: true } to ease into it instead) map.setBearing(90) map.setBearing(90, { animate: true, onComplete: () => console.log("aligned") }) // Lock / unlock user rotation at runtime map.setRotationEnabled(false)

For totem projects the per‑device angle is configured on the backend and returned by getConfiguration in Configuration.mapRotations, indexed by the totem’s place id (mapvxId). Resolve the totem (e.g. with getPlaceDetail(alias)), read its angle and apply it:

const config = await sdk.getConfiguration(parentPlaceId) const totem = await sdk.getPlaceDetail("PA11") // alias -> place const angle = config.mapRotations?.[totem.mapvxId]?.angle ?? config.initialBearing ?? 0 map.setBearing(angle)

Restrict user interactions (static screen)

To present a static screen where the visitor can only zoom in and out — no rotation and no panning — disable the corresponding gestures. Every flag defaults to true, so only set the ones you want to turn off.

const map = sdk.createMap(container, { center: { lat: 4.666918, lng: -74.053065 }, zoom: 19, rotateEnabled: false, // no rotation dragPan: false, // no panning scrollZoom: true, // keep wheel/trackpad zoom (default) })

Available interaction flags on MapConfig:

  • interactive — master switch; false disables all pan/zoom/rotate at once
  • rotateEnabled — drag/touch/keyboard rotation (keeps pinch‑to‑zoom when false)
  • dragPan — pan by dragging/swiping
  • scrollZoom — scroll wheel / trackpad zoom
  • doubleClickZoom — double‑click / double‑tap zoom
  • touchZoomRotate — pinch zoom on touch devices
  • keyboard — keyboard pan/zoom/rotate shortcuts

The same restrictions can be toggled at runtime:

map.setRotationEnabled(false) map.setPanEnabled(false) map.setScrollZoomEnabled(true)

Restrict the navigable area

Bounds demo: restricted navigation area

Use setMaxBounds when the user should stay inside a known area:

map.setMaxBounds( [ { lat: 4.6675, lng: -74.0525 }, { lat: 4.6663, lng: -74.0537 }, ], { onComplete: () => { console.log("Bounds locked") }, } )

Camera movements via updateCamera are automatically constrained — if you try to move outside the bounds, the map snaps back to the nearest valid position:

// This will be constrained to stay within bounds map.updateCamera({ center: { lat: 0, lng: 0 }, duration: 1000 }) // The camera snaps back instead of moving to (0, 0)

You can also check programmatically if a coordinate is inside the bounds:

const isAllowed = map.isInsideBounds({ lat: 4.6669, lng: -74.053, })

Switch map label language at runtime

Language switch demo: es to en and back

map.setLang("en")

This updates the language used in map layers without re-creating the map instance.

Clear tile cache after a style update

map.clearTileCache()

This is useful when:

  • the backend style was updated
  • tiles look stale or corrupted
  • you want to force visible tiles to be requested again

Tile cache configuration at creation time

const map = sdk.createMap(container, { center: { lat: 4.666918, lng: -74.053065 }, zoom: 17, tileCache: { enabled: true, maxTiles: 600, ttlMs: 60 * 60 * 1000, persistToServiceWorker: true, preloadAdjacentZooms: false, }, })
Last updated on