Dynamic overlay measurement
Register sidebars, bottom panels and other interface elements and let the package measure their real DOM geometry instead of relying on hard-coded dimensions.
A lightweight and fully typed viewport and safe-area manager for MapLibre GL JS applications with dynamic UI overlays.
Measure real interface geometry, keep viewport calculations synchronized with changing layouts and fit map content into the area users can actually see.
MapLibre GL JS provides powerful camera APIs, but it does not know which parts of the map are covered by application UI. Sidebars, bottom sheets and floating detail panels can therefore hide markers or important map content even when the camera technically fits the map container.
jamit-maplibre-viewport connects DOM layout geometry with MapLibre camera operations. Registered overlays are measured automatically, layout changes are observed and camera helpers can work with the map area that remains genuinely visible to the user.
Viewport-aware geometry and camera helpers for MapLibre applications with dynamic interface overlays.
Register sidebars, bottom panels and other interface elements and let the package measure their real DOM geometry instead of relying on hard-coded dimensions.
ResizeObserver keeps viewport geometry synchronized when registered overlays or the map container change size.
fitCoordinates() searches for a camera position and zoom level where all supplied coordinates remain visible outside registered UI obstacles.
Partial overlays only block the area they actually occupy. Free space beside a panel can remain available for map content.
Read the currently available viewport padding and safe area through a fully typed API.
Use viewport-aware fitBounds(), fitCoordinates(), flyTo() and easeTo() operations without manually synchronizing UI dimensions with MapLibre.
Add configurable spacing around the map edges and registered obstacles so markers and other important content do not sit directly against interface elements.
The package works directly with MapLibre and standard DOM APIs and does not require Vue, Nuxt, React or another frontend framework.
Import the package safely in SSR environments. Browser globals are only accessed when actual map and overlay elements are used.
Resize and toggle interface overlays and see how the available map area changes. Fit multiple locations into the space that remains visible to the user.
Resize this panel and run Fit Coordinates again.
Toggle the sidebar, resize the bottom panel and compare MapLibre camera operations while the viewport manager keeps track of the real interface geometry.
The viewport manager connects real interface geometry with camera calculations in five focused steps.
Connect the DOM elements that cover your map.
The viewport manager measures their actual position and dimensions relative to the map container.
ResizeObserver detects dynamic layout changes without polling.
Overlay rectangles, safe areas and additional consumer padding are converted into usable viewport geometry.
Camera helpers use the calculated geometry to keep important map content visible.
Install jamit-maplibre-viewport together with MapLibre GL JS.
pnpm add jamit-maplibre-viewport maplibre-glnpm install jamit-maplibre-viewport maplibre-glMapLibre GL JS is provided as a peer dependency.
Supported: MapLibre GL JS >= 5.6.0 < 7
Create the MapLibre map as usual and pass the map instance to createMapLibreViewport().
import { Map } from 'maplibre-gl';
import { createMapLibreViewport } from 'jamit-maplibre-viewport';
const map = new Map({
container: 'map',
style: 'https://demotiles.maplibre.org/style.json',
center: [13.405, 52.52],
zoom: 11,
});
const viewport = createMapLibreViewport(map);Register the UI elements that cover parts of the map. The package measures their real DOM rectangles and keeps their geometry synchronized.
viewport.addOverlay({
id: 'sidebar',
element: sidebar,
edge: 'left',
});
viewport.addOverlay({
id: 'bottom-panel',
element: bottomPanel,
edge: 'bottom',
});fitCoordinates() uses the actual registered obstacle rectangles instead of reducing the complete map to simple rectangular edge padding.
The solver searches for the highest fitting zoom level and a valid camera center while keeping the supplied coordinates outside registered overlays.
viewport.fitCoordinates(
[
[13.405, 52.52],
[13.35, 52.5],
[13.46, 52.54],
],
{
padding: 40,
maxZoom: 14,
duration: 800,
},
);Use familiar camera operations while the viewport manager provides geometry-aware padding and positioning.
fitBounds() uses a rectangular edge-safe area and delegates the final operation to MapLibre.
viewport.fitBounds(bounds, {
padding: 40,
maxZoom: 14,
duration: 800,
});Use MapLibre-style flyTo() options while applying the current viewport geometry.
viewport.flyTo({
center: [13.405, 52.52],
zoom: 14,
padding: 40,
duration: 1200,
});Move the camera smoothly while respecting the currently calculated viewport padding.
viewport.easeTo({
center: [13.46, 52.54],
zoom: 13,
padding: 40,
duration: 800,
});Access the currently calculated viewport padding and rectangular safe area through the typed geometry API.
const padding = viewport.getPadding();{
top: 0,
right: 0,
bottom: 180,
left: 320,
}const safeArea = viewport.getSafeArea();{
x: 320,
y: 0,
width: 960,
height: 540,
}Registered overlays and the map container are monitored with ResizeObserver. When their dimensions change, the internal viewport geometry is invalidated and recalculated before the next camera operation.
This makes collapsing sidebars, responsive panels and expanding bottom sheets possible without maintaining hard-coded layout dimensions in the map logic.
refresh() forces an immediate geometry recalculation. It does not automatically move the map camera.
viewport.refresh();
viewport.fitCoordinates(coordinates, {
padding: 40,
});Destroying the viewport manager disconnects observers, cancels scheduled animation frames and releases internal references.
viewport.destroy();jamit-maplibre-viewport depends on MapLibre and standard browser APIs, not on a UI framework.
The package can be imported in server-side rendered applications without requiring window, document, HTMLElement or ResizeObserver during module evaluation.
DOM access starts only when a viewport manager interacts with an actual MapLibre instance and registered elements.
The package has been validated against MapLibre GL JS 5.6 and 6.0 using type checks, automated tests and library builds.
Unsupported scenarios are rejected explicitly to prevent incorrect or misleading camera results.
fitCoordinates() currently supports only maps with bearing 0 and pitch 0. Rotated or tilted maps intentionally produce a clear error instead of an incorrect camera result.
bearing = 0
pitch = 0Coordinate groups that cross the international date line are currently rejected intentionally. Full world-wrapping support is planned for a future version.
[
[179, 10],
[-179, 10],
]Dynamic overlay measurement, ResizeObserver-based layout tracking, safe-area calculation, viewport-aware camera helpers and obstacle-aware coordinate fitting are fully implemented and covered by automated tests.
The package is publicly available on npm and includes support for MapLibre GL JS 5.6 and 6.0, TypeScript definitions, SSR-safe imports, automated CI checks and a live interactive demo.
The complete source code, automated tests, MapLibre demo and release history are available in the public GitHub repository.