feat: remove fill when district pop up is close

This commit is contained in:
vergiLgood1 2025-05-14 12:31:31 +07:00
parent 5808758855
commit f4b6d19eb2
1 changed files with 161 additions and 145 deletions

View File

@ -11,7 +11,7 @@ import TimelineLayer from "./timeline-layer"
import type { ICrimes, IIncidentLogs } from "@/app/_utils/types/crimes" import type { ICrimes, IIncidentLogs } from "@/app/_utils/types/crimes"
import type { IDistrictFeature } from "@/app/_utils/types/map" import type { IDistrictFeature } from "@/app/_utils/types/map"
import { createFillColorExpression, processCrimeDataByDistrict } from "@/app/_utils/map" import { createFillColorExpression, getCrimeRateColor, processCrimeDataByDistrict } from "@/app/_utils/map"
import UnclusteredPointLayer from "./uncluster-layer" import UnclusteredPointLayer from "./uncluster-layer"
import { toast } from "sonner" import { toast } from "sonner"
@ -153,17 +153,20 @@ export default function Layers({
easing: (t) => t * (2 - t), easing: (t) => t * (2 - t),
}) })
if (map.getLayer("clusters")) { if (map.getLayer("clusters")) {
map.getMap().setLayoutProperty("clusters", "visibility", "visible") map.getMap().setLayoutProperty("clusters", "visibility", "visible")
} }
if (map.getLayer("unclustered-point")) {
map.getMap().setLayoutProperty("unclustered-point", "visibility", "visible") if (map.getLayer("unclustered-point")) {
} map.getMap().setLayoutProperty("unclustered-point", "visibility", "visible")
}
if (map.getLayer("district-fill")) { if (map.getLayer("district-fill")) {
const fillColorExpression = createFillColorExpression(null, crimeDataByDistrict) const fillColorExpression = createFillColorExpression(null, crimeDataByDistrict)
map.getMap().setPaintProperty("district-fill", "fill-color", fillColorExpression as any) map.getMap().setPaintProperty("district-fill", "fill-color", fillColorExpression as any)
} }
} }
}, [map, crimeDataByDistrict]) }, [map, crimeDataByDistrict])
@ -213,6 +216,19 @@ export default function Layers({
0, 0,
]) ])
map.getMap().setPaintProperty("district-extrusion", "fill-extrusion-color", [
"case",
["has", "kode_kec"],
[
"match",
["get", "kode_kec"],
focusedDistrictId || "",
"transparent",
"transparent",
],
"transparent",
])
if (progress < 1) { if (progress < 1) {
animationRef.current = requestAnimationFrame(animate) animationRef.current = requestAnimationFrame(animate)
} else { } else {
@ -270,7 +286,7 @@ export default function Layers({
easing: (t) => t * (2 - t), easing: (t) => t * (2 - t),
}) })
// Hide clusters when focusing on a district // Hide clusters when focusing on a district
if (map.getLayer("clusters")) { if (map.getLayer("clusters")) {
map.getMap().setLayoutProperty("clusters", "visibility", "none") map.getMap().setLayoutProperty("clusters", "visibility", "none")
} }
@ -289,16 +305,16 @@ export default function Layers({
const customEvent = e as CustomEvent const customEvent = e as CustomEvent
if (!map || !customEvent.detail) return if (!map || !customEvent.detail) return
const { longitude, latitude, zoom, bearing, pitch, duration } = customEvent.detail const { longitude, latitude, zoom, bearing, pitch, duration } = customEvent.detail
map.flyTo({ map.flyTo({
center: [longitude, latitude], center: [longitude, latitude],
zoom: zoom || 15, zoom: zoom || 15,
bearing: bearing || 0, bearing: bearing || 0,
pitch: pitch || 45, pitch: pitch || 45,
duration: duration || 2000, duration: duration || 2000,
}) })
} }
mapboxMap.getCanvas().addEventListener("mapbox_fly_to", handleFlyToEvent as EventListener) mapboxMap.getCanvas().addEventListener("mapbox_fly_to", handleFlyToEvent as EventListener)
@ -316,93 +332,93 @@ export default function Layers({
const customEvent = e as CustomEvent const customEvent = e as CustomEvent
console.log("Received incident_click event in layers:", customEvent.detail) console.log("Received incident_click event in layers:", customEvent.detail)
if (!customEvent.detail) { if (!customEvent.detail) {
console.error("Empty incident click event data") console.error("Empty incident click event data")
return return
} }
// Set the marker interaction flag to prevent district selection // Set the marker interaction flag to prevent district selection
isInteractingWithMarker.current = true isInteractingWithMarker.current = true
const incidentId = customEvent.detail.id || customEvent.detail.incidentId || customEvent.detail.incident_id const incidentId = customEvent.detail.id || customEvent.detail.incidentId || customEvent.detail.incident_id
if (!incidentId) { if (!incidentId) {
console.error("No incident ID found in event data:", customEvent.detail) console.error("No incident ID found in event data:", customEvent.detail)
return return
} }
console.log("Looking for incident with ID:", incidentId) console.log("Looking for incident with ID:", incidentId)
let foundIncident: ICrimeIncident | undefined let foundIncident: ICrimeIncident | undefined
if ( if (
customEvent.detail.latitude !== undefined && customEvent.detail.latitude !== undefined &&
customEvent.detail.longitude !== undefined && customEvent.detail.longitude !== undefined &&
customEvent.detail.category !== undefined customEvent.detail.category !== undefined
) { ) {
foundIncident = { foundIncident = {
id: incidentId, id: incidentId,
district: customEvent.detail.district, district: customEvent.detail.district,
category: customEvent.detail.category, category: customEvent.detail.category,
type_category: customEvent.detail.type, type_category: customEvent.detail.type,
description: customEvent.detail.description, description: customEvent.detail.description,
status: customEvent.detail.status || "Unknown", status: customEvent.detail.status || "Unknown",
timestamp: customEvent.detail.timestamp ? new Date(customEvent.detail.timestamp) : undefined, timestamp: customEvent.detail.timestamp ? new Date(customEvent.detail.timestamp) : undefined,
latitude: customEvent.detail.latitude, latitude: customEvent.detail.latitude,
longitude: customEvent.detail.longitude, longitude: customEvent.detail.longitude,
address: customEvent.detail.address, address: customEvent.detail.address,
} }
} else { } else {
for (const crime of crimes) { for (const crime of crimes) {
for (const incident of crime.crime_incidents) { for (const incident of crime.crime_incidents) {
if (incident.id === incidentId || incident.id?.toString() === incidentId?.toString()) { if (incident.id === incidentId || incident.id?.toString() === incidentId?.toString()) {
console.log("Found matching incident:", incident) console.log("Found matching incident:", incident)
foundIncident = { foundIncident = {
id: incident.id, id: incident.id,
district: crime.districts.name, district: crime.districts.name,
description: incident.description, description: incident.description,
status: incident.status || "unknown", status: incident.status || "unknown",
timestamp: incident.timestamp, timestamp: incident.timestamp,
category: incident.crime_categories.name, category: incident.crime_categories.name,
type_category: incident.crime_categories.type, type_category: incident.crime_categories.type,
address: incident.locations.address, address: incident.locations.address,
latitude: incident.locations.latitude, latitude: incident.locations.latitude,
longitude: incident.locations.longitude, longitude: incident.locations.longitude,
} }
break break
} }
} }
if (foundIncident) break if (foundIncident) break
} }
} }
if (!foundIncident) { if (!foundIncident) {
console.error("Could not find incident with ID:", incidentId) console.error("Could not find incident with ID:", incidentId)
isInteractingWithMarker.current = false isInteractingWithMarker.current = false
return return
}
if (!foundIncident.latitude || !foundIncident.longitude) {
console.error("Found incident has invalid coordinates:", foundIncident)
isInteractingWithMarker.current = false
return
}
console.log("Setting selected incident:", foundIncident)
// Clear district selection when showing an incident
setSelectedDistrict(null)
selectedDistrictRef.current = null
setFocusedDistrictId(null)
setSelectedIncident(foundIncident)
// Reset the marker interaction flag after a delay
setTimeout(() => {
isInteractingWithMarker.current = false
}, 1000)
} }
if (!foundIncident.latitude || !foundIncident.longitude) {
console.error("Found incident has invalid coordinates:", foundIncident)
isInteractingWithMarker.current = false
return
}
console.log("Setting selected incident:", foundIncident)
// Clear district selection when showing an incident
setSelectedDistrict(null)
selectedDistrictRef.current = null
setFocusedDistrictId(null)
setSelectedIncident(foundIncident)
// Reset the marker interaction flag after a delay
setTimeout(() => {
isInteractingWithMarker.current = false
}, 1000)
}
mapboxMap.getCanvas().addEventListener("incident_click", handleIncidentClickEvent as EventListener) mapboxMap.getCanvas().addEventListener("incident_click", handleIncidentClickEvent as EventListener)
document.addEventListener("incident_click", handleIncidentClickEvent as EventListener) document.addEventListener("incident_click", handleIncidentClickEvent as EventListener)
@ -450,64 +466,64 @@ export default function Layers({
if (districtCrime) { if (districtCrime) {
const selectedYearNum = year ? Number.parseInt(year) : new Date().getFullYear() const selectedYearNum = year ? Number.parseInt(year) : new Date().getFullYear()
let demographics = districtCrime.districts.demographics?.find((d) => d.year === selectedYearNum) let demographics = districtCrime.districts.demographics?.find((d) => d.year === selectedYearNum)
if (!demographics && districtCrime.districts.demographics?.length) { if (!demographics && districtCrime.districts.demographics?.length) {
demographics = districtCrime.districts.demographics.sort((a, b) => b.year - a.year)[0] demographics = districtCrime.districts.demographics.sort((a, b) => b.year - a.year)[0]
} }
let geographics = districtCrime.districts.geographics?.find((g) => g.year === selectedYearNum) let geographics = districtCrime.districts.geographics?.find((g) => g.year === selectedYearNum)
if (!geographics && districtCrime.districts.geographics?.length) { if (!geographics && districtCrime.districts.geographics?.length) {
const validGeographics = districtCrime.districts.geographics const validGeographics = districtCrime.districts.geographics
.filter((g) => g.year !== null) .filter((g) => g.year !== null)
.sort((a, b) => (b.year || 0) - (a.year || 0)) .sort((a, b) => (b.year || 0) - (a.year || 0))
geographics = validGeographics.length > 0 ? validGeographics[0] : districtCrime.districts.geographics[0] geographics = validGeographics.length > 0 ? validGeographics[0] : districtCrime.districts.geographics[0]
} }
if (!demographics || !geographics) { if (!demographics || !geographics) {
console.error("Missing district data:", { demographics, geographics }) console.error("Missing district data:", { demographics, geographics })
return return
} }
const crime_incidents = districtCrime.crime_incidents const crime_incidents = districtCrime.crime_incidents
.filter((incident) => filterCategory === "all" || incident.crime_categories.name === filterCategory) .filter((incident) => filterCategory === "all" || incident.crime_categories.name === filterCategory)
.map((incident) => ({ .map((incident) => ({
id: incident.id, id: incident.id,
timestamp: incident.timestamp, timestamp: incident.timestamp,
description: incident.description, description: incident.description,
status: incident.status || "", status: incident.status || "",
category: incident.crime_categories.name, category: incident.crime_categories.name,
type: incident.crime_categories.type || "", type: incident.crime_categories.type || "",
address: incident.locations.address || "", address: incident.locations.address || "",
latitude: incident.locations.latitude, latitude: incident.locations.latitude,
longitude: incident.locations.longitude, longitude: incident.locations.longitude,
})) }))
const updatedDistrict: IDistrictFeature = { const updatedDistrict: IDistrictFeature = {
...selectedDistrictRef.current, ...selectedDistrictRef.current,
number_of_crime: crimeDataByDistrict[districtId]?.number_of_crime || 0, number_of_crime: crimeDataByDistrict[districtId]?.number_of_crime || 0,
level: crimeDataByDistrict[districtId]?.level || selectedDistrictRef.current.level, level: crimeDataByDistrict[districtId]?.level || selectedDistrictRef.current.level,
demographics: { demographics: {
number_of_unemployed: demographics.number_of_unemployed, number_of_unemployed: demographics.number_of_unemployed,
population: demographics.population, population: demographics.population,
population_density: demographics.population_density, population_density: demographics.population_density,
year: demographics.year, year: demographics.year,
}, },
geographics: { geographics: {
address: geographics.address || "", address: geographics.address || "",
land_area: geographics.land_area || 0, land_area: geographics.land_area || 0,
year: geographics.year || 0, year: geographics.year || 0,
latitude: geographics.latitude, latitude: geographics.latitude,
longitude: geographics.longitude, longitude: geographics.longitude,
}, },
crime_incidents, crime_incidents,
selectedYear: year, selectedYear: year,
selectedMonth: month, selectedMonth: month,
} }
selectedDistrictRef.current = updatedDistrict selectedDistrictRef.current = updatedDistrict
setSelectedDistrict((prevDistrict) => { setSelectedDistrict((prevDistrict) => {
if ( if (