import { useState } from "react"; import { GripHorizontal, ChevronUp, Eye, EyeOff } from "lucide-react"; import L from "leaflet"; import { useAtom } from "jotai"; import { isOpenMapsetDialogAtom, selectedMapsetAtom } from "../../../../state/mapset-dialog"; import { useQuery } from "@tanstack/react-query"; import { ActiveLayer, removeLayerAtom, toggleLayerAtom, setLayerOpacityAtom } from "../../../../state/active-layers"; import { mapAtom } from "../../../../state/map"; import mapsetApi from "@/shared/services/mapset"; import { LegendDisplay } from "./legend-display"; import { OpacityControl } from "./opacity-control"; import { LayerActions } from "./layer-actions"; import dynamic from "next/dynamic"; const ChoroplethControl = dynamic(() => import("./choropleth-control"), { ssr: false, loading: () =>
, }); interface LayerControlItemProps { layer: ActiveLayer; layerInstance?: L.Layer; onZoom: (bounds?: L.LatLngBoundsExpression | null) => void; } export const LayerControlItem = ({ layer, layerInstance, onZoom }: LayerControlItemProps) => { const [isExpanded, setIsExpanded] = useState(false); // Drive slider from global state so newly created instances pick it up const opacity = layer.settings.opacity; const [, setIsOpenDialog] = useAtom(isOpenMapsetDialogAtom); const [, setSelectedMapset] = useAtom(selectedMapsetAtom); const [, removeLayer] = useAtom(removeLayerAtom); const [, toggleLayer] = useAtom(toggleLayerAtom); const [, setLayerOpacity] = useAtom(setLayerOpacityAtom); const { data: mapset } = useQuery({ queryKey: ["mapset", layer.source.id], queryFn: () => mapsetApi.getMapsetById(layer.source.id.toString(), { skipAuth: true }).then((res) => { return res; }), }); const [map] = useAtom(mapAtom); const handleOpacityChange = (value: number[]) => { const next = value[0]; // Update the Leaflet instance immediately for responsiveness if (layerInstance && layerInstance instanceof L.TileLayer.WMS) { layerInstance.setOpacity(next); } if (layerInstance && layerInstance instanceof L.GeoJSON) { layerInstance.setStyle({ fillOpacity: next, opacity: next, }); } // Persist in global state so new/reattached instances get correct opacity setLayerOpacity({ layerId: layer.id, opacity: next }); }; const handleInfo = () => { if (!mapset) return; setSelectedMapset(mapset); setIsOpenDialog(true); }; const handleToggleVisibility = () => { if (!map) return; toggleLayer(layer.id); if (layerInstance) { if (layer.settings.visible) { layerInstance.remove(); } else { layerInstance.addTo(map); } } }; function toLatLngBounds(bounds: L.LatLngBoundsExpression): L.LatLngBounds { if ("getSouthWest" in bounds && "getNorthEast" in bounds) { return bounds as L.LatLngBounds; } return L.latLngBounds(bounds as L.LatLngExpression[]); } const handleDownloadImage = () => { if (!layer.layer.url || !layer.layer.layers) return; const rawBounds = layer.layer.bounds ?? map?.getBounds() ?? null; if (!rawBounds) return; const bounds = toLatLngBounds(rawBounds); const southWest = bounds.getSouthWest(); const northEast = bounds.getNorthEast(); const bbox = [southWest.lng, southWest.lat, northEast.lng, northEast.lat].join(","); const width = 1024; const height = 768; const downloadUrl = `${layer.layer.url}?service=WMS&version=1.1.1&request=GetMap&layers=${layer.layer.layers}&styles=&bbox=${bbox}&width=${width}&height=${height}&srs=EPSG:4326&format=image/png&transparent=true`; window.open(downloadUrl, "_blank"); }; return (
{!isExpanded && ( )} {!isExpanded &&
}
{isExpanded && (
removeLayer(layer.id)} onDownload={handleDownloadImage} /> {mapset?.layer_type === "point" && }
)}
); };