"use client" import { IBaseLayerProps } from "@/app/_utils/types/map" import { useEffect, useRef } from "react" export default function FlyToHandler({ map }: Pick) { // Track active animations const animationRef = useRef(null) useEffect(() => { if (!map) return const handleFlyToEvent = (e: CustomEvent) => { if (!map || !e.detail) return const { longitude, latitude, zoom, bearing, pitch, duration } = e.detail map.flyTo({ center: [longitude, latitude], zoom: zoom || 15, bearing: bearing || 0, pitch: pitch || 45, duration: duration || 2000, }) // Cancel any existing animation if (animationRef.current) { cancelAnimationFrame(animationRef.current) } // Add a highlight or pulse effect to the target incident try { if (map.getLayer("target-incident-highlight")) { map.removeLayer("target-incident-highlight") } if (map.getSource("target-incident-highlight")) { map.removeSource("target-incident-highlight") } map.addSource("target-incident-highlight", { type: "geojson", data: { type: "Feature", geometry: { type: "Point", coordinates: [longitude, latitude], }, properties: {}, }, }) map.addLayer({ id: "target-incident-highlight", source: "target-incident-highlight", type: "circle", paint: { "circle-radius": ["interpolate", ["linear"], ["zoom"], 10, 10, 15, 15, 20, 20], "circle-color": "#ff0000", "circle-opacity": 0.7, "circle-stroke-width": 2, "circle-stroke-color": "#ffffff", }, }) // Add a slower pulsing effect let size = 10 let frameCount = 0 const animationSpeed = 3; // Higher value = slower animation (skip frames) const animatePulse = () => { if (!map || !map.getLayer("target-incident-highlight")) { if (animationRef.current) { cancelAnimationFrame(animationRef.current) animationRef.current = null } return } frameCount++; // Only update size every few frames to slow down the animation if (frameCount % animationSpeed === 0) { size = (size % 20) + 0.5; // Smaller increment for smoother, slower animation } map.setPaintProperty("target-incident-highlight", "circle-radius", [ "interpolate", ["linear"], ["zoom"], 10, size, 15, size * 1.5, 20, size * 2, ]) animationRef.current = requestAnimationFrame(animatePulse) } animationRef.current = requestAnimationFrame(animatePulse) } catch (error) { console.error("Error adding highlight effect:", error) } } // Listen for the custom fly-to event map.getCanvas().addEventListener("mapbox_fly_to", handleFlyToEvent as EventListener) // Also listen on the document to ensure we catch the event document.addEventListener("mapbox_fly_to", handleFlyToEvent as EventListener) return () => { if (map && map.getCanvas()) { map.getCanvas().removeEventListener("mapbox_fly_to", handleFlyToEvent as EventListener) } document.removeEventListener("mapbox_fly_to", handleFlyToEvent as EventListener) // Clean up animation on unmount if (animationRef.current) { cancelAnimationFrame(animationRef.current) animationRef.current = null } } }, [map]) return null }