import type { Map as MapLibreMap, PaddingOptions } from "maplibre-gl"; import { getWorkbenchCameraPadding } from "../layout/workbench-layout"; import { WATER_NETWORK_GLOBAL_VIEW } from "./sources"; type LngLatBounds = [[number, number], [number, number]]; type WebMercatorBbox = readonly [number, number, number, number]; export type NetworkViewParams = { bbox3857: WebMercatorBbox; }; const WEB_MERCATOR_RADIUS = 6378137; const GLOBAL_VIEW_MAX_ZOOM = 13; const GLOBAL_VIEW_PADDING: PaddingOptions = { top: 96, right: 48, bottom: 48, left: 48 }; export function getWorkbenchPadding(leftPanelOpen: boolean, rightPanelOpen: boolean): PaddingOptions { return getWorkbenchCameraPadding(1280, { agentOpen: leftPanelOpen, conditionOpen: rightPanelOpen }); } export function getResponsiveWorkbenchPadding( map: MapLibreMap, leftPanelOpen: boolean, rightPanelOpen: boolean ): PaddingOptions { const width = getMapViewportSize(map).width; return getResponsivePadding( map, getWorkbenchCameraPadding(width, { agentOpen: leftPanelOpen, conditionOpen: rightPanelOpen }) ); } export function fitNetworkBounds( map: MapLibreMap, viewParams: NetworkViewParams = WATER_NETWORK_GLOBAL_VIEW, padding: PaddingOptions = GLOBAL_VIEW_PADDING ) { map.fitBounds( getLngLatBoundsFromBbox3857(viewParams.bbox3857), { padding: getResponsivePadding(map, padding), maxZoom: GLOBAL_VIEW_MAX_ZOOM, duration: 600 } ); } export function getResponsivePadding(map: MapLibreMap, padding: PaddingOptions): PaddingOptions { const { width, height } = getMapViewportSize(map); const horizontalPadding = padding.left + padding.right; const verticalPadding = padding.top + padding.bottom; const maxHorizontalPadding = width * 0.58; const maxVerticalPadding = height * 0.58; const horizontalScale = horizontalPadding > 0 ? maxHorizontalPadding / horizontalPadding : 1; const verticalScale = verticalPadding > 0 ? maxVerticalPadding / verticalPadding : 1; const scale = Math.min(1, horizontalScale, verticalScale); if (scale >= 1) { return padding; } return { top: Math.round(padding.top * scale), right: Math.round(padding.right * scale), bottom: Math.round(padding.bottom * scale), left: Math.round(padding.left * scale) }; } function getMapViewportSize(map: MapLibreMap) { const canvas = map.getCanvas(); return { width: canvas.clientWidth || canvas.width, height: canvas.clientHeight || canvas.height }; } function getLngLatBoundsFromBbox3857(bbox3857: WebMercatorBbox): LngLatBounds { const [minX, minY, maxX, maxY] = bbox3857; return [ webMercatorToLngLat(minX, minY), webMercatorToLngLat(maxX, maxY) ]; } function webMercatorToLngLat(x: number, y: number): [number, number] { const lng = (x / WEB_MERCATOR_RADIUS) * (180 / Math.PI); const lat = (2 * Math.atan(Math.exp(y / WEB_MERCATOR_RADIUS)) - Math.PI / 2) * (180 / Math.PI); return [lng, lat]; }