import { useRef, useState, useEffect, useCallback } from "react"; import * as Cesium from "cesium"; import { createCesiumProvider } from "../factories/cesium-provider"; import { leafletZoomToCesiumHeight } from "../utils/cesium"; import { activeBasemapAtom } from "../state/active-basemap"; import { useAtom, useAtomValue } from "jotai"; import { mapSettingsAtom } from "../state/map-settings"; import { basemapConfig } from "../config/basemap-config"; export const useCesiumMap = () => { const cesiumContainer = useRef(null); const viewerRef = useRef(null); const [isMapInitialized, setIsMapInitialized] = useState(false); const activeBasemap = useAtomValue(activeBasemapAtom); const [mapSettings] = useAtom(mapSettingsAtom); useEffect(() => { if (!cesiumContainer.current || viewerRef.current) return; try { const viewer = new Cesium.Viewer(cesiumContainer.current, { baseLayerPicker: false, animation: false, timeline: false, geocoder: false, homeButton: false, navigationHelpButton: false, sceneModePicker: false, requestRenderMode: true, maximumRenderTimeChange: Infinity, }); viewerRef.current = viewer; viewer.camera.setView({ destination: Cesium.Cartesian3.fromDegrees( mapSettings.center[1], mapSettings.center[0], leafletZoomToCesiumHeight(mapSettings.zoomLevel) ), }); viewer.scene.globe.enableLighting = true; setIsMapInitialized(true); } catch (error) { console.error("Error initializing Cesium:", error); } return () => { if (viewerRef.current) { viewerRef.current.destroy(); viewerRef.current = null; } }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { if (!viewerRef.current || !isMapInitialized) return; const applyBasemap = async () => { const viewer = viewerRef.current; const currentConfig = basemapConfig[activeBasemap]; if (!viewer) return; if (!currentConfig?.cesium) { console.error( `Missing Cesium configuration for basemap: ${activeBasemap}` ); return; } try { const layers = viewer.imageryLayers; layers.removeAll(); viewer.terrainProvider = new Cesium.EllipsoidTerrainProvider(); const provider = await createCesiumProvider(currentConfig.cesium); if (provider) { layers.addImageryProvider(provider as Cesium.ImageryProvider); viewer.scene.requestRender(); } else { console.error("Failed to create imagery provider"); } } catch (error) { console.error("Error applying basemap:", error); } }; applyBasemap(); }, [activeBasemap, isMapInitialized]); const flyToLocation = useCallback( ( latitude: number, longitude: number, height?: number, duration?: number ) => { if (!viewerRef.current) return; const finalHeight = height ?? leafletZoomToCesiumHeight(mapSettings.zoomLevel); viewerRef.current.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees( longitude, latitude, finalHeight ), duration: duration ?? 2.0, }); }, [mapSettings.zoomLevel] ); return { cesiumContainer, viewerRef, isMapInitialized, activeBasemap, flyToLocation, }; };