import type { Map as MapLibreMap } from "maplibre-gl"; import { Home, Minus, Navigation2, Plus, type LucideIcon } from "lucide-react"; import { type ReactNode, type RefObject, useCallback, useEffect, useState } from "react"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/shared/ui/tooltip"; import { cn } from "@/shared/ui/cn"; import { CAMERA_MODE_ANGLE_TOLERANCE, getCombinedCameraAction, setThreeDimensionalNavigation } from "./camera-actions"; import { MAP_CONTROL_HOVER_CLASS_NAME, mapOptionInteractionVariants, MAP_CONTROL_RADIUS_CLASS_NAME, MAP_ICON_CELL_RADIUS_CLASS_NAME, MAP_CONTROL_SURFACE_CLASS_NAME } from "./map-control-styles"; type MapZoomProps = { mapRef: RefObject; mapReady: boolean; onHome: () => void; reducedMotion?: boolean; className?: string; }; export function MapZoom({ mapRef, mapReady, onHome, reducedMotion = false, className = "" }: MapZoomProps) { const [orientation, setOrientation] = useState({ bearing: 0, pitch: 0 }); const is3d = orientation.pitch > CAMERA_MODE_ANGLE_TOLERANCE; const cameraAction = getCombinedCameraAction(orientation.bearing, orientation.pitch); useEffect(() => { const map = mapRef.current; if (!map || !mapReady) return; const syncOrientation = () => { const nextOrientation = { bearing: map.getBearing(), pitch: map.getPitch() }; setOrientation(nextOrientation); setThreeDimensionalNavigation(map, nextOrientation.pitch > CAMERA_MODE_ANGLE_TOLERANCE); }; syncOrientation(); map.on("pitch", syncOrientation); map.on("rotate", syncOrientation); return () => { map.off("pitch", syncOrientation); map.off("rotate", syncOrientation); }; }, [mapRef, mapReady]); const handleCameraMode = useCallback(() => { const map = mapRef.current; if (!map) return; const action = getCombinedCameraAction(map.getBearing(), map.getPitch()); const duration = reducedMotion ? 0 : 350; if (action === "enter-3d") { setThreeDimensionalNavigation(map, true); map.easeTo({ pitch: window.matchMedia("(max-width: 639px)").matches ? 45 : 50, duration }); return; } if (action === "reset-north") { map.easeTo({ bearing: 0, duration }); return; } setThreeDimensionalNavigation(map, false); map.easeTo({ pitch: 0, bearing: 0, duration }); }, [mapRef, reducedMotion]); const handleZoomIn = useCallback(() => { mapRef.current?.zoomIn({ duration: 260 }); }, [mapRef]); const handleZoomOut = useCallback(() => { mapRef.current?.zoomOut({ duration: 260 }); }, [mapRef]); return (
} label={ cameraAction === "reset-north" ? "恢复北向" : cameraAction === "exit-3d" ? "切换到二维" : "切换到三维" } pressed={is3d} disabled={!mapReady} onClick={handleCameraMode} />
); } type ControlButtonProps = { icon?: LucideIcon; content?: ReactNode; pressed?: boolean; label: string; disabled: boolean; onClick: () => void; }; function ControlButton({ icon: Icon, content, pressed, label, disabled, onClick }: ControlButtonProps) { return ( {label} ); } function CompassModeIndicator({ bearing, pitch, mode }: { bearing: number; pitch: number; mode: "2D" | "3D"; }) { return ( ); } function Divider() { return