refactor: streamline map constants and enhance animation handling in layers
This commit is contained in:
parent
6c96c1140c
commit
8a1582c994
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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<number | null>(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),
|
||||
})
|
||||
|
||||
|
|
|
@ -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({
|
|||
</TabsContent>
|
||||
</Tabs>
|
||||
</Card>
|
||||
{/* Connection line */}
|
||||
<div
|
||||
className="absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-full"
|
||||
style={{
|
||||
width: '2px',
|
||||
height: '20px',
|
||||
backgroundColor: 'red',
|
||||
boxShadow: '0 0 4px rgba(0, 0, 0, 0.3)'
|
||||
}}
|
||||
/>
|
||||
{/* Connection dot */}
|
||||
<div
|
||||
className="absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-full"
|
||||
style={{
|
||||
width: '6px',
|
||||
height: '6px',
|
||||
backgroundColor: 'red',
|
||||
borderRadius: '50%',
|
||||
marginTop: '20px',
|
||||
boxShadow: '0 0 4px rgba(0, 0, 0, 0.3)'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Popup>
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue