feat: enhance SidebarInfoTab with detailed map layers and add timeline layer functionality to CrimeMap; update TimelineLegend and TimelinePopup styles

This commit is contained in:
vergiLgood1 2025-05-07 08:01:07 +07:00
parent 4cc01babf1
commit 05ba4ab920
4 changed files with 145 additions and 13 deletions

View File

@ -1,5 +1,5 @@
import React from 'react'
import { Layers, Info, Eye, Filter, MapPin, AlertTriangle, AlertCircle } from 'lucide-react'
import { Layers, Info, Eye, Filter, MapPin, AlertTriangle, AlertCircle, Clock, Flame, MapPinned, Users, Map, Box, Thermometer } from 'lucide-react'
import { Card, CardContent } from "@/app/_components/ui/card"
import { Separator } from "@/app/_components/ui/separator"
import { CRIME_RATE_COLORS } from "@/app/_utils/const/map"
@ -44,6 +44,112 @@ export function SidebarInfoTab() {
</Card>
</SidebarSection>
<SidebarSection title="Map Layers" icon={<Map className="h-4 w-4 text-blue-400" />}>
<Card className="bg-gradient-to-r from-zinc-800/80 to-zinc-900/80 border border-white/10">
<CardContent className="p-4 text-xs space-y-4">
<div className="space-y-2">
<h4 className="flex items-center gap-2 font-medium text-sm">
<AlertCircle className="h-4 w-4 text-cyan-400" />
<span>Incidents Layer</span>
</h4>
<p className="text-white/70 pl-6">
Shows individual crime incidents as map markers. Each marker represents a single crime report and is color-coded by category.
Click on any marker to see detailed information about the incident.
</p>
</div>
<div className="space-y-2">
<h4 className="flex items-center gap-2 font-medium text-sm">
<Box className="h-4 w-4 text-pink-400" />
<span>Clusters Layer</span>
</h4>
<p className="text-white/70 pl-6">
Groups nearby incidents into clusters for better visibility at lower zoom levels. Numbers show incident count in each cluster.
Clusters are color-coded by size: blue (small), yellow (medium), pink (large).
Click on a cluster to zoom in and see individual incidents.
</p>
<div className="flex items-center gap-6 pl-6 pt-1">
<div className="flex items-center gap-2">
<div className="w-4 h-4 rounded-full bg-[#51bbd6]"></div>
<span>1-5</span>
</div>
<div className="flex items-center gap-2">
<div className="w-4 h-4 rounded-full bg-[#f1f075]"></div>
<span>6-15</span>
</div>
<div className="flex items-center gap-2">
<div className="w-4 h-4 rounded-full bg-[#f28cb1]"></div>
<span>15+</span>
</div>
</div>
</div>
<div className="space-y-2">
<h4 className="flex items-center gap-2 font-medium text-sm">
<Thermometer className="h-4 w-4 text-orange-400" />
<span>Heatmap Layer</span>
</h4>
<p className="text-white/70 pl-6">
Shows crime density across regions, with warmer colors (red, orange) indicating higher crime concentration
and cooler colors (blue) showing lower concentration. Useful for identifying crime hotspots.
</p>
<div className="pl-6 pt-1">
<div className="h-2 w-full rounded-full bg-gradient-to-r from-blue-600 via-yellow-400 to-red-600"></div>
<div className="flex justify-between text-[10px] mt-1 text-white/70">
<span>Low</span>
<span>Density</span>
<span>High</span>
</div>
</div>
</div>
<div className="space-y-2">
<h4 className="flex items-center gap-2 font-medium text-sm">
<Users className="h-4 w-4 text-blue-400" />
<span>Units Layer</span>
</h4>
<p className="text-white/70 pl-6">
Displays police and security units as blue circles with connecting lines to nearby incidents.
Units are labeled and can be clicked to show more information and related incident details.
</p>
<div className="flex items-center gap-2 pl-6 pt-1">
<div className="w-4 h-4 rounded-full border-2 border-white bg-[#1e40af]"></div>
<span>Police/Security Unit</span>
</div>
</div>
<div className="space-y-2">
<h4 className="flex items-center gap-2 font-medium text-sm">
<Clock className="h-4 w-4 text-yellow-400" />
<span>Timeline Layer</span>
</h4>
<p className="text-white/70 pl-6">
Shows time patterns of crime incidents with color-coded circles representing average times of day when
incidents occur in each district. Click for detailed time distribution analysis.
</p>
<div className="flex flex-wrap gap-x-5 gap-y-2 pl-6 pt-1">
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-full bg-[#FFEB3B]"></div>
<span>Morning</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-full bg-[#FF9800]"></div>
<span>Afternoon</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-full bg-[#3F51B5]"></div>
<span>Evening</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-full bg-[#263238]"></div>
<span>Night</span>
</div>
</div>
</div>
</CardContent>
</Card>
</SidebarSection>
<SidebarSection title="About" icon={<Info className="h-4 w-4 text-green-400" />}>
<Card className="bg-gradient-to-r from-zinc-800/80 to-zinc-900/80 border border-white/10">
<CardContent className="p-4 text-xs">

View File

@ -37,6 +37,9 @@ export default function CrimeMap() {
const [isTimelapsePlaying, setisTimelapsePlaying] = useState(false)
const [isSearchActive, setIsSearchActive] = useState(false)
const [showUnitsLayer, setShowUnitsLayer] = useState(false)
const [showClusters, setShowClusters] = useState(false)
const [showHeatmap, setShowHeatmap] = useState(false)
const [showUnclustered, setShowUnclustered] = useState(true)
const [useAllYears, setUseAllYears] = useState<boolean>(false)
const [useAllMonths, setUseAllMonths] = useState<boolean>(false)
@ -153,6 +156,18 @@ export default function CrimeMap() {
const handleControlChange = (controlId: ITooltips) => {
setActiveControl(controlId);
if (controlId === "clusters") {
setShowClusters(true)
} else {
setShowClusters(false)
}
if (controlId === "incidents") {
setShowUnclustered(true)
} else {
setShowUnclustered(false)
}
if (controlId === "search") {
setIsSearchActive(prev => !prev);
}
@ -244,12 +259,19 @@ export default function CrimeMap() {
selectedYear={selectedYear}
selectedMonth={selectedMonth}
/>
<div className="absolute bottom-20 right-0 z-10 p-2">
<MapLegend position="bottom-right" />
</div>
{isFullscreen && (
<div className="absolute bottom-20 right-0 z-20 p-2">
{showClusters && (
<MapLegend position="bottom-right" />
)}
{showUnclustered && !showClusters && (
<MapLegend position="bottom-right" />
)}
</div>
)}
{isFullscreen && showUnitsLayer && (
<div className="absolute bottom-40 right-0 z-10 p-2">
<div className="absolute bottom-20 right-0 z-10 p-2">
<UnitsLegend
categories={categories}
position="bottom-right"
@ -258,7 +280,7 @@ export default function CrimeMap() {
)}
{isFullscreen && showTimelineLayer && (
<div className="absolute bottom-40 right-0 z-10 p-2">
<div className="absolute flex bottom-20 right-0 z-10 p-2">
<TimelineLegend position="bottom-right" />
</div>
)}

View File

@ -1,7 +1,7 @@
"use client"
import { Card } from "@/app/_components/ui/card"
import { Clock, Moon, Sun } from "lucide-react"
import { Clock, Moon, Sun, Sunset } from "lucide-react"
interface TimelineLegendProps {
position?: "top-right" | "top-left" | "bottom-right" | "bottom-left"
@ -18,36 +18,40 @@ export default function TimelineLegend({
}
return (
<Card className={`absolute z-10 bg-black/80 border-gray-700 shadow-lg p-3 ${positionClasses[position]}`}>
<div className="flex flex-col gap-2">
<h3 className="text-sm font-medium text-white mb-2 flex items-center gap-2">
<Card className={`flex z-10 bg-black/80 border-gray-700 shadow-lg p-4 ${positionClasses[position]}`}>
<div className="flex flex-col gap-3">
<h3 className="text-sm font-medium text-white flex items-center gap-2">
<Clock className="h-4 w-4" />
<span>Incident Time Patterns</span>
</h3>
<div className="grid grid-cols-2 gap-x-4 gap-y-2">
<div className="grid grid-cols-2 gap-y-3">
<div className="flex items-center gap-2">
<Sun className="h-4 w-4 text-[#FFEB3B]" />
<div className="w-3 h-3 rounded-full bg-[#FFEB3B]"></div>
<span className="text-xs text-white">Morning (5am-12pm)</span>
</div>
<div className="flex items-center gap-2">
<Sun className="h-4 w-4 text-[#FF9800]" />
<div className="w-3 h-3 rounded-full bg-[#FF9800]"></div>
<span className="text-xs text-white">Afternoon (12pm-5pm)</span>
</div>
<div className="flex items-center gap-2">
<Sunset className="h-4 w-4 text-[#3F51B5]" />
<div className="w-3 h-3 rounded-full bg-[#3F51B5]"></div>
<span className="text-xs text-white">Evening (5pm-9pm)</span>
</div>
<div className="flex items-center gap-2">
<Moon className="h-4 w-4 text-gray-400" />
<div className="w-3 h-3 rounded-full bg-[#263238]"></div>
<span className="text-xs text-white">Night (9pm-5am)</span>
</div>
</div>
<div className="text-xs text-gray-400 mt-1">
<div className="text-xs text-gray-300 mt-1 border-t border-gray-700 pt-2">
Circles show average incident time. Click for details.
</div>
</div>

View File

@ -59,7 +59,7 @@ export default function TimelinePopup({
anchor="bottom"
closeOnClick={false}
onClose={onClose}
className="z-10"
className="timeline-popup z-10"
maxWidth="300px"
>
<div className="relative">