Skip to content
glyphcss

Camera & Navigation

Loading terrain…

The Alps start tilted and turned. Drag to move; Ctrl+drag or right-drag changes tilt and bearing. Wheel zoom is disabled in these article examples; try it in the maps workbench.

const map = createGlyphMap(host, {
view, projection,
controls: { drag: true, wheel: true, tilt: true },
tilt: 55, bearing: 35,
});

All three control flags default to true. drag controls pan/orbit, wheel controls every zoom gesture, and tilt controls pitch and bearing independently of dragging.

InputAction
Drag / one fingerPan a sheet; orbit a globe
Wheel / two-finger pinchZoom
Ctrl+drag / right-dragVertical: tilt; horizontal: bearing
Two-finger twistBearing
Two fingers moving verticallyTilt
Double-tap / two-finger tapZoom in / out
Double-tap, hold, dragOne-handed zoom; down zooms in
Clickclick event; lngLat is null off-surface

Touch pinch and twist combine; a recognised tilt stays exclusive until release. Disable all controls to let touch gestures scroll the article through the map.

map.setView({ center: [-58.38, -34.6], span: 0.06 });
map.fitBounds({ west: 5.9, east: 10.5, south: 45.8, north: 47.8 });
const view = map.getView();
const maxSpan = map.getMaxSpan();
  • center is [longitude, latitude]; span is degrees across the grid.
  • minSpan defaults to 0.001 degrees.
  • A sheet’s getMaxSpan() keeps the viewport covered; its ceiling changes with shape, tilt, bearing, projection, and centre.
  • A globe’s maximum is its projection domain width.
  • Explicit maxSpan disables the sheet cover limit and pan clamp, allowing margins.
map.setTilt(55);
map.setBearing(137);
const pose = [map.getTilt(), map.getBearing(), map.getMaxTilt()];

tilt pitches around the surface point at the view centre. Sheets default to 40 degrees; globes to 0. getTilt() reports the applied, clamped value; zooming back in restores a previously limited request.

The pivot uses the drawn ground: the same triangle-sampled, elevation-windowed terrain used to plant features, including exaggeration. A supplied groundElevation wins; without ground, the pivot stays at the datum. Terrain arriving later re-anchors before its first render and preserves the geographic centre and shared URL. Surrounding content can shift as the new relief appears. map.project(map.getView().center) lands at the centre of the grid at every pitch and span (within a cell with snapPan). unproject() inverts that same ground surface; a local solve can return null where it has no answer.

getMaxTilt() is 85 degrees on sheets; globes use a scale-dependent horizon limit capped at 85. Read it after zooming. bearing defaults to 0 (north up); 90 puts east up. getBearing() normalizes to [0, 360).

await map.flyTo({ center: [-58.38, -34.6], span: 0.06 }, { durationMs: 1200 });
await map.flyTo({ bounds: { west: 5.9, east: 10.5, south: 45.8, north: 47.8 } });
await map.idle();
const text = map.scene.output.textContent;

A target uses centre/span or bounds, never both. durationMs: 0 jumps immediately; bow: 1 disables the mid-flight zoom-out. Call idle() after a mutation to await tiles, geometry, motion, and transitions before reading output. It has no timeout.

Change projections with setProjection.

await map.flyTo({ center: [-58.3816, -34.6037], span: 0.01 });
await map.idle();
map.setWalk({ eyeHeight: 1.7, far: 600 });
const walk = map.getWalk();
map.setWalk(null); // restore the map view

Mount OSM streets and buildings first. Walk mode requires an orbit projection such as glyphMapGlobe; sheets throw RangeError. Enter through the handle, not construction options. Entry sets span from far; the application should enforce the recommended maximum entry span of 0.05 degrees.

OptionDefault
eyeHeight1.7 m
fov56 degrees horizontal
near / far0.5 / 600 m
speed6 m/s
maxPitch84 degrees from horizontal
collision / skytrue / true
  • WASD/arrows move; Shift runs ×3; hold G to pass through buildings.
  • Mouse pointer lock looks; drag is the fallback. Esc releases lock; wheel does nothing.
  • Collision uses fill-extrusion footprints; fills remain walkable.
  • The sky requires solid mode; sky: false removes it.
  • Calling setWalk again reconfigures; setWalk(null) restores the saved view, tilt, bearing, and camera.

createGlyphMap({ ..., snapPan: true }) holds tiny pans on one rendered cell lattice. Flat maps translate by whole output cells; globes quantize rotation on a local tangent lattice, so shapes near the limb can still change. The camera translation is exact on flat maps. The renderer’s screen-anchored shading dither can still change terrain glyphs during a whole-cell step. The held centre (getView() and shared links) stays exact. Zoom, tilt, bearing and grid changes start a new lattice without snapping that change. Walking bypasses snapping. Use map.setSnapPan(boolean) to toggle it. The /maps View folder enables Snap pan by default and saves the choice in shared links. Omission in the package keeps continuous pans.

createGlyphMap({ ..., compositorPan: true }) renders a quarter-view margin of extra cells and translates the text container during mouse or one-finger pans and inertial glide. Cell size stays fixed; base, detail, and stroke-overlay text move together. Labels, markers, and other DOM hotspots hide until settle. Compass and minimap UI remain fixed.

The cache refreshes at 80% of either margin. Globe pans approximate rotation with the screen displacement of the cached view centre and refresh after 2° of rotation, so features away from the centre can distort briefly. Refreshes can change screen-anchored shading dither. Tile arrivals may force earlier renders; unloaded tiles are not prefetched just for the extra margin.

Release and glide rest restore the normal grid and render the actual view (with its existing snapPan lattice). Zoom, tilt, bearing, projection, resize, and font changes invalidate the cache. Walking bypasses it. With this option on, scene.setInteracting does not downscale the text. Use map.setCompositorPan(boolean) and map.getCompositorPan() at runtime. The package defaults off; /maps defaults Compositor pan on in the View folder and preserves the toggle in shared links.