'use client' import { useRef, useEffect, useState, useCallback } from 'react' import Globe from 'react-globe.gl' export interface GlobePoint { lat: number lng: number id: string label: string color: string size?: number } interface GlobeVisualizationProps { points: GlobePoint[] onPointClick: (point: GlobePoint) => void height?: number autoRotate?: boolean focusLat?: number focusLng?: number } export function GlobeVisualization({ points, onPointClick, height = 500, autoRotate = true, focusLat, focusLng, }: GlobeVisualizationProps) { const globeRef = useRef(null) const containerRef = useRef(null) const [containerWidth, setContainerWidth] = useState(0) // Responsive width useEffect(() => { if (!containerRef.current) return const observer = new ResizeObserver((entries) => { for (const entry of entries) { setContainerWidth(entry.contentRect.width) } }) observer.observe(containerRef.current) setContainerWidth(containerRef.current.clientWidth) return () => observer.disconnect() }, []) // Configure controls after globe is ready const handleGlobeReady = useCallback(() => { const globe = globeRef.current if (!globe) return const controls = globe.controls() if (controls) { controls.autoRotate = autoRotate controls.autoRotateSpeed = 0.5 controls.enableDamping = true controls.dampingFactor = 0.1 } // Set initial view globe.pointOfView({ lat: focusLat ?? 20, lng: focusLng ?? 0, altitude: 2.5 }, 0) }, [autoRotate, focusLat, focusLng]) // Focus on specific coordinates when they change useEffect(() => { if (globeRef.current && focusLat != null && focusLng != null) { globeRef.current.pointOfView({ lat: focusLat, lng: focusLng, altitude: 1.5 }, 1000) } }, [focusLat, focusLng]) return (
{containerWidth > 0 && ( Math.max(0.15, Math.min(0.6, (d.size || 1) * 0.12))} pointLabel={(d: any) => `
${d.label}
`} onPointClick={(point: any) => onPointClick(point as GlobePoint)} onGlobeReady={handleGlobeReady} enablePointerInteraction={true} /> )}
) }