feat: task 2.8 camera control trio + follow toggle
- src/map/core/map-pref-store.ts: mapFollow boolean (default true) +
setter. Persisted via trm-map-prefs.
- src/map/core/camera/default-camera.tsx: <MapDefaultCamera /> fits
the snapshot's bounds once per activeEventId change. Uses a
fittedFor ref; resets to null when activeEventId becomes null.
Single-point events centre+zoom 12; multi-point fitBounds with
padding capped at min(canvas*0.1, 80).
- src/map/core/camera/selected-device.tsx: <MapSelectedDevice />
pans+zooms on selection change, smooth pans on subsequent position
updates with mapFollow on. Separate effect listens for user-gesture
movestart (originalEvent truthy) and flips mapFollow off.
- src/map/core/camera/map-camera.tsx: <MapCamera coordinates> imperative
one-shot. Phase 2 doesn't use it; primitive for replay (Phase 4) and
future "fit to all" UI.
- src/map/core/follow-toggle.tsx: <FollowToggle /> icon-button using
Lucide Locate/LocateOff. Sits below the trails toggle.
- src/routes/_authed/monitor.tsx: renders FollowToggle, MapDefaultCamera,
MapSelectedDevice.
Deviations:
- Manual-pan listener uses an inline { originalEvent?: unknown } type
instead of MapLibre's MapMouseEvent|MapTouchEvent union (typing
friction across version bumps).
- MapDefaultCamera clears fittedFor on activeEventId === null so
re-selecting the same event later re-fits.
Bundle: main 395KB / 120KB gz, no measurable change.
This commit is contained in:
@@ -8,6 +8,8 @@ import {
|
||||
usePositionStore,
|
||||
} from '@/live';
|
||||
import { BasemapSwitcher } from '@/map/core/basemap-switcher';
|
||||
import { MapDefaultCamera, MapSelectedDevice } from '@/map/core/camera';
|
||||
import { FollowToggle } from '@/map/core/follow-toggle';
|
||||
import { MapView } from '@/map/core/map-view';
|
||||
import { TrailsToggle } from '@/map/core/trails-toggle';
|
||||
import { MapPositions } from '@/map/layers/map-positions';
|
||||
@@ -58,6 +60,7 @@ function MonitorPage() {
|
||||
/>
|
||||
<BasemapSwitcher />
|
||||
<TrailsToggle />
|
||||
<FollowToggle />
|
||||
{/*
|
||||
Layer order matters — MapLibre paints in addLayer() call order.
|
||||
<MapTrails /> mounts first so its line layer renders below the
|
||||
@@ -65,6 +68,13 @@ function MonitorPage() {
|
||||
*/}
|
||||
<MapTrails />
|
||||
<MapPositions />
|
||||
{/*
|
||||
Camera components are side-effect-only (return null). They sit
|
||||
at the end so they react to whatever <MapPositions /> just
|
||||
surfaced (selected device, latest positions).
|
||||
*/}
|
||||
<MapDefaultCamera />
|
||||
<MapSelectedDevice />
|
||||
</MapView>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user