From 89c13e8cad676480128bc1c3cbf8afd2f72404de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AD=8F=E9=A3=8E?= Date: Tue, 24 Mar 2026 23:31:30 +0800 Subject: [PATCH] feat(map): focus selected marker at max zoom and tighten collapsed device panel --- frontend/src/routes/_layout/index.tsx | 60 +++++++++++++++++++++------ 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/frontend/src/routes/_layout/index.tsx b/frontend/src/routes/_layout/index.tsx index 583bae7..8c8d157 100644 --- a/frontend/src/routes/_layout/index.tsx +++ b/frontend/src/routes/_layout/index.tsx @@ -67,6 +67,10 @@ type TelemetrySnapshot = { type ConnectionState = "connecting" | "live" | "retrying" type BaseMapType = "osm" | "amap" | "amap-satellite" +type MapControlBridge = { + __mapFitAll?: () => void + __mapFocusDevice?: (coordinate: [number, number]) => void +} /* ---------- constants ---------- */ @@ -338,17 +342,38 @@ function FitBoundsControl({ coordinates: Array<[number, number]> }) { const map = useMap() - const fitAll = () => { + const fitAll = useCallback(() => { if (!coordinates.length) return if (coordinates.length === 1) { map.setView(coordinates[0], 14, { animate: true }) } else { map.fitBounds(coordinates, { padding: [40, 40] }) } - } - // expose via a ref so the outside button can call it - const ref = window as unknown as Record void> - ref.__mapFitAll = fitAll + }, [coordinates, map]) + + const focusDevice = useCallback( + (coordinate: [number, number]) => { + const maxZoom = map.getMaxZoom() + const targetZoom = Number.isFinite(maxZoom) ? maxZoom : 18 + map.setView(coordinate, targetZoom, { animate: true }) + }, + [map], + ) + + useEffect(() => { + const ref = window as unknown as MapControlBridge + ref.__mapFitAll = fitAll + ref.__mapFocusDevice = focusDevice + return () => { + if (ref.__mapFitAll === fitAll) { + delete ref.__mapFitAll + } + if (ref.__mapFocusDevice === focusDevice) { + delete ref.__mapFocusDevice + } + } + }, [fitAll, focusDevice]) + return null } @@ -490,9 +515,14 @@ function Dashboard() { [devicesWithCoords, isGcj02], ) - const handleDeviceClick = useCallback((deviceId: string) => { - setActiveDeviceId(deviceId) - }, []) + const handleDeviceClick = useCallback( + (deviceId: string, coordinate: [number, number]) => { + setActiveDeviceId(deviceId) + const mapBridge = window as unknown as MapControlBridge + mapBridge.__mapFocusDevice?.(coordinate) + }, + [], + ) const isLive = status === "live" @@ -574,11 +604,12 @@ function Dashboard() { {devicesWithCoords.map((device) => { const isOffline = checkIsOffline(device.last_event_time) const isSelected = activeDeviceId === device.device_id - const [projLat, projLon] = projectCoord( + const projectedCoordinate = projectCoord( device.lat as number, device.lon as number, isGcj02, ) + const [projLat, projLon] = projectedCoordinate const color = deviceMarkerColor(device.fix_status, isOffline) const icon = buildDeviceIcon(color, isSelected, isOffline) @@ -587,7 +618,8 @@ function Dashboard() { position={[projLat, projLon]} icon={icon} eventHandlers={{ - click: () => handleDeviceClick(device.device_id), + click: () => + handleDeviceClick(device.device_id, projectedCoordinate), }} key={device.device_id} > @@ -639,12 +671,14 @@ function Dashboard() {
- + setIsPanelExpanded(!isPanelExpanded)} > - + Selected Device {activeDevice?.signal_health && !isPanelExpanded &&