From 8a1582c99411426bdff6586952f71e4299dc6d9d Mon Sep 17 00:00:00 2001 From: vergiLgood1 Date: Wed, 14 May 2025 12:04:21 +0700 Subject: [PATCH] refactor: streamline map constants and enhance animation handling in layers --- .../_components/map/layers/district-layer.tsx | 40 +++++----- .../app/_components/map/layers/layers.tsx | 78 +++++++++++++++++-- .../_components/map/pop-up/district-popup.tsx | 38 ++------- sigap-website/app/_utils/const/map.ts | 16 ++-- 4 files changed, 111 insertions(+), 61 deletions(-) diff --git a/sigap-website/app/_components/map/layers/district-layer.tsx b/sigap-website/app/_components/map/layers/district-layer.tsx index e404de5..b5418ff 100644 --- a/sigap-website/app/_components/map/layers/district-layer.tsx +++ b/sigap-website/app/_components/map/layers/district-layer.tsx @@ -88,29 +88,29 @@ export default function DistrictFillLineLayer({ } // Wait a moment before selecting the new district to ensure clean transitions - setTimeout(() => { - const district = processDistrictFeature(feature, e, districtId, crimeDataByDistrict, crimes, year, month) - if (!district || !setFocusedDistrictId) return + // setTimeout(() => { + // const district = processDistrictFeature(feature, e, districtId, crimeDataByDistrict, crimes, year, month) + // if (!district || !setFocusedDistrictId) return - setFocusedDistrictId(district.id) + // setFocusedDistrictId(district.id) - // Fly to the new district - map.flyTo({ - center: [district.longitude, district.latitude], - zoom: 12.5, - pitch: 75, - bearing: 0, - duration: 1500, - easing: (t) => t * (2 - t), // easeOutQuad - }) + // // Fly to the new district + // map.flyTo({ + // center: [district.longitude, district.latitude], + // zoom: 12.5, + // pitch: 75, + // bearing: 0, + // duration: 1500, + // easing: (t) => t * (2 - t), // easeOutQuad + // }) - // Use onDistrictClick if available, otherwise fall back to onClick - if (onDistrictClick) { - onDistrictClick(district) - } else if (onClick) { - onClick(district) - } - }, 100) + // // Use onDistrictClick if available, otherwise fall back to onClick + // if (onDistrictClick) { + // onDistrictClick(district) + // } else if (onClick) { + // onClick(district) + // } + // }, 100) return } diff --git a/sigap-website/app/_components/map/layers/layers.tsx b/sigap-website/app/_components/map/layers/layers.tsx index 82f13a2..35c68a0 100644 --- a/sigap-website/app/_components/map/layers/layers.tsx +++ b/sigap-website/app/_components/map/layers/layers.tsx @@ -2,7 +2,7 @@ import { useState, useRef, useEffect, useCallback } from "react" import { useMap } from "react-map-gl/mapbox" -import { BASE_BEARING, BASE_PITCH, BASE_ZOOM, MAPBOX_TILESET_ID } from "@/app/_utils/const/map" +import { BASE_BEARING, BASE_DURATION, BASE_PITCH, BASE_ZOOM, MAPBOX_TILESET_ID } from "@/app/_utils/const/map" import DistrictPopup from "../pop-up/district-popup" import DistrictExtrusionLayer from "./district-extrusion-layer" import ClusterLayer from "./cluster-layer" @@ -91,6 +91,7 @@ export default function Layers({ showEWS = true, sourceType = "cbt", }: LayersProps) { + const animationRef = useRef(null) const { current: map } = useMap() if (!map) { @@ -148,7 +149,7 @@ export default function Layers({ zoom: BASE_ZOOM, pitch: BASE_PITCH, bearing: BASE_BEARING, - duration: 1500, + duration: BASE_DURATION, easing: (t) => t * (2 - t), }) @@ -166,10 +167,75 @@ export default function Layers({ } }, [map, crimeDataByDistrict]) + + const animateExtrusionDown = () => { + if (!map || !map.getLayer("district-extrusion") || !focusedDistrictId) { + return + } + + if (animationRef.current) { + cancelAnimationFrame(animationRef.current) + animationRef.current = null + } + + // Get the current height from the layer (default to 800 if not found) + let currentHeight = 800 + + try { + const paint = map.getPaintProperty("district-extrusion", "fill-extrusion-height") + if (Array.isArray(paint) && paint.length > 0) { + // Try to extract the current height from the expression + const idx = paint.findIndex((v) => v === focusedDistrictId) + if (idx !== -1 && typeof paint[idx + 1] === "number") { + currentHeight = paint[idx + 1] + } + } + } catch { + // fallback to default + } + + const startHeight = currentHeight + const targetHeight = 0 + const duration = 700 + const startTime = performance.now() + + const animate = (currentTime: number) => { + const elapsed = currentTime - startTime + const progress = Math.min(elapsed / duration, 1) + const easedProgress = progress * (2 - progress) + const newHeight = startHeight + (targetHeight - startHeight) * easedProgress + + try { + map.getMap().setPaintProperty("district-extrusion", "fill-extrusion-height", [ + "case", + ["has", "kode_kec"], + ["match", ["get", "kode_kec"], focusedDistrictId, newHeight, 0], + 0, + ]) + + if (progress < 1) { + animationRef.current = requestAnimationFrame(animate) + } else { + animationRef.current = null + } + + } catch (error) { + if (animationRef.current) { + cancelAnimationFrame(animationRef.current) + animationRef.current = null + } + } + } + + animationRef.current = requestAnimationFrame(animate) + } + const handleCloseDistrictPopup = useCallback(() => { console.log("Closing district popup") + + animateExtrusionDown() handlePopupClose() - }, [handlePopupClose]) + }, [handlePopupClose, animateExtrusionDown]) const handleCloseIncidentPopup = useCallback(() => { console.log("Closing incident popup") @@ -197,10 +263,10 @@ export default function Layers({ if (map && feature.longitude && feature.latitude) { map.flyTo({ center: [feature.longitude, feature.latitude], - zoom: 12, - pitch: 45, + zoom: 12.5, + pitch: 60, bearing: 0, - duration: 1500, + duration: BASE_DURATION, easing: (t) => t * (2 - t), }) diff --git a/sigap-website/app/_components/map/pop-up/district-popup.tsx b/sigap-website/app/_components/map/pop-up/district-popup.tsx index dbca8a0..3e6b3bd 100644 --- a/sigap-website/app/_components/map/pop-up/district-popup.tsx +++ b/sigap-website/app/_components/map/pop-up/district-popup.tsx @@ -47,14 +47,14 @@ export default function DistrictPopup({ const [activeTab, setActiveTab] = useState("overview") // Add debug log when the component is rendered - useEffect(() => { - console.log("DistrictPopup mounted:", { - district: district.name, - coords: [longitude, latitude], - year, - month - }); - }, [district, longitude, latitude, year, month]); + // useEffect(() => { + // console.log("DistrictPopup mounted:", { + // district: district.name, + // coords: [longitude, latitude], + // year, + // month + // }); + // }, [district, longitude, latitude, year, month]); // Extract all crime incidents from the district data and apply filtering if needed const allCrimeIncidents = useMemo(() => { @@ -332,28 +332,6 @@ export default function DistrictPopup({ - {/* Connection line */} -
- {/* Connection dot */} -
) diff --git a/sigap-website/app/_utils/const/map.ts b/sigap-website/app/_utils/const/map.ts index e963071..1a41d32 100644 --- a/sigap-website/app/_utils/const/map.ts +++ b/sigap-website/app/_utils/const/map.ts @@ -1,10 +1,16 @@ -export const BASE_ZOOM = 9.5; // Default zoom level for the map -export const BASE_PITCH = 0; // Default pitch for the map -export const BASE_BEARING = 0; // Default bearing for the map + +export const MAPBOX_ACCESS_TOKEN = process.env.NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN; +export const MAPBOX_TILESET_ID = process.env.NEXT_PUBLIC_MAPBOX_TILESET_ID; + +export const BASE_ZOOM = 9.5; +export const BASE_PITCH = 0; +export const BASE_BEARING = 0; export const BASE_LATITUDE = -8.17; // Default latitude for the map center (Jember region) export const BASE_LONGITUDE = 113.65; // Default longitude for the map center (Jember region) -export const MAPBOX_ACCESS_TOKEN = process.env.NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN; -export const MAPBOX_TILESET_ID = process.env.NEXT_PUBLIC_MAPBOX_TILESET_ID; // Replace with your tileset ID +export const BASE_DURATION = 2000; // Default duration for map flyTo animation +export const PITCH_3D = 60; // Default pitch for 3D view +export const ZOOM_3D = 12.5; // Default zoom for 3D view + // export const CRIME_RATE_COLORS = { // low: '#FFB74D', // green