diff --git a/sigap-website/app/_components/map/controls/top/search-control.tsx b/sigap-website/app/_components/map/controls/top/search-control.tsx index f405c36..47bfaad 100644 --- a/sigap-website/app/_components/map/controls/top/search-control.tsx +++ b/sigap-website/app/_components/map/controls/top/search-control.tsx @@ -256,19 +256,40 @@ export default function SearchTooltip({ onControlChange, activeControl, crimes = const handleFlyToIncident = () => { if (!selectedSuggestion || !selectedSuggestion.locations.latitude || !selectedSuggestion.locations.longitude) return; - const flyToEvent = new CustomEvent('incident_click', { + // First, trigger a separate mapbox_fly_to event to handle the camera movement + const flyToMapEvent = new CustomEvent('mapbox_fly_to', { detail: { longitude: selectedSuggestion.locations.longitude, latitude: selectedSuggestion.locations.latitude, - id: selectedSuggestion.id, zoom: 15, - description: selectedSuggestion.description, - status: selectedSuggestion.status + bearing: 0, + pitch: 45, + duration: 2000, }, bubbles: true }); - document.dispatchEvent(flyToEvent); + document.dispatchEvent(flyToMapEvent); + + // Wait for the fly animation to complete before showing the popup + setTimeout(() => { + // Then trigger the incident_click event to show the popup + const incidentEvent = new CustomEvent('incident_click', { + detail: { + id: selectedSuggestion.id, + longitude: selectedSuggestion.locations.longitude, + latitude: selectedSuggestion.locations.latitude, + description: selectedSuggestion.description, + status: selectedSuggestion.status, + timestamp: selectedSuggestion.timestamp, + crime_categories: selectedSuggestion.crime_categories + }, + bubbles: true + }); + + document.dispatchEvent(incidentEvent); + }, 2100); // Slightly longer than the fly animation duration + setShowInfoBox(false); setSelectedSuggestion(null); toggleSearch(); diff --git a/sigap-website/app/_components/map/crime-map.tsx b/sigap-website/app/_components/map/crime-map.tsx index 29a5388..dab9bab 100644 --- a/sigap-website/app/_components/map/crime-map.tsx +++ b/sigap-website/app/_components/map/crime-map.tsx @@ -185,6 +185,46 @@ export default function CrimeMap() { }; }, [filteredCrimes]); + // Set up event listener for fly-to map control + useEffect(() => { + const handleMapFlyTo = (e: CustomEvent) => { + if (!e.detail) { + console.error("Invalid fly-to data:", e.detail); + return; + } + + const { longitude, latitude, zoom, bearing, pitch, duration } = e.detail; + + // Find the map instance + const mapInstance = mapContainerRef.current?.querySelector('.mapboxgl-map'); + if (!mapInstance) { + console.error("Map instance not found"); + return; + } + + // Create and dispatch a custom event that MapView component will listen for + const mapboxEvent = new CustomEvent('mapbox_fly', { + detail: { + center: [longitude, latitude], + zoom: zoom || 15, + bearing: bearing || 0, + pitch: pitch || 45, + duration: duration || 2000 + }, + bubbles: true + }); + + mapInstance.dispatchEvent(mapboxEvent); + }; + + // Add event listener + document.addEventListener('mapbox_fly_to', handleMapFlyTo as EventListener); + + return () => { + document.removeEventListener('mapbox_fly_to', handleMapFlyTo as EventListener); + }; + }, []); + // Handle year-month timeline change const handleTimelineChange = useCallback((year: number, month: number, progress: number) => { setSelectedYear(year) diff --git a/sigap-website/app/_components/map/map.tsx b/sigap-website/app/_components/map/map.tsx index a1be92c..206fcbe 100644 --- a/sigap-website/app/_components/map/map.tsx +++ b/sigap-website/app/_components/map/map.tsx @@ -1,7 +1,7 @@ "use client" import type React from "react" -import { useState, useCallback, useRef } from "react" +import { useState, useCallback, useRef, useEffect } from "react" import { type ViewState, Map, type MapRef, NavigationControl, GeolocateControl } from "react-map-gl/mapbox" import { FullscreenControl } from "react-map-gl/mapbox" import { BASE_BEARING, BASE_LATITUDE, BASE_LONGITUDE, BASE_PITCH, BASE_ZOOM, MAPBOX_STYLES, type MapboxStyle } from "@/app/_utils/const/map" @@ -79,6 +79,34 @@ export default function MapView({ [onMoveEnd], ) + useEffect(() => { + if (!mapRef.current) return; + + const mapElement = mapRef.current.getMap().getContainer(); + + // Handle fly to event + const handleMapFly = (e: CustomEvent) => { + if (!e.detail || !mapRef.current) return; + + const { center, zoom, bearing, pitch, duration } = e.detail; + + mapRef.current.flyTo({ + center, + zoom, + bearing, + pitch, + duration, + essential: true + }); + }; + + mapElement.addEventListener('mapbox_fly', handleMapFly as EventListener); + + return () => { + mapElement.removeEventListener('mapbox_fly', handleMapFly as EventListener); + }; + }, [mapRef.current]); + return (