TypeScript 87.7%
CSS 12.3%
1/**2 * Author: Simon-Pierre Boucher3 * Contact: contact@spboucher.ai4 * Project: Groupe Ka / Ka Maps5 *6 * URL state serialization: /map?lat=46.8139&lng=-71.2080&zoom=137 * Each app decides which extra parameters it exposes; Ka Maps only owns8 * the camera portion so URLs stay short and stable.9 */1011export interface CameraUrlState {12 lat: number;13 lng: number;14 zoom: number;15}1617/** Serialize camera state into URLSearchParams (mutates a copy, returns it). */18export function cameraToParams(19 state: CameraUrlState,20 base?: URLSearchParams,21): URLSearchParams {22 const params = new URLSearchParams(base);23 params.set("lat", state.lat.toFixed(5));24 params.set("lng", state.lng.toFixed(5));25 params.set("zoom", trimZoom(state.zoom));26 return params;27}2829/** Parse camera state from URLSearchParams; null when absent or malformed. */30export function cameraFromParams(params: URLSearchParams): CameraUrlState | null {31 const rawLat = params.get("lat");32 const rawLng = params.get("lng");33 const rawZoom = params.get("zoom");34 if (rawLat === null || rawLng === null || rawZoom === null) return null;35 const lat = Number(rawLat);36 const lng = Number(rawLng);37 const zoom = Number(rawZoom);38 if (!Number.isFinite(lat) || !Number.isFinite(lng) || !Number.isFinite(zoom)) return null;39 if (lat < -90 || lat > 90 || lng < -180 || lng > 180) return null;40 return { lat, lng, zoom: Math.min(22, Math.max(0, zoom)) };41}4243function trimZoom(zoom: number): string {44 return (Math.round(zoom * 100) / 100).toString();45}46