feat: implement hotspot visualization on map
- Add HotspotSeverity type and HotspotWithSeverity interface - Implement getHotspots() method in analyticsService with severity calculation - Add hotspot layer to MapView component with color-coded circles - Create hotspot markers with severity icons and report count badges - Add detailed hotspot popups showing report count, severity score, radius, and dates - Implement hotspot toggle control in MapFilters with loading state - Add hotspot severity legend to MapFilters - Integrate hotspot data fetching in MapPage with sample fallback data - Color-code hotspot boundaries: yellow (low), orange (medium/high), red (critical) - Display hotspot statistics in interactive popups Implements task 12: Create hotspot visualization Requirements: 3.2, 3.3, 3.5
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useState } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { MapView, MapFilters } from '@/components/map';
|
||||
import type { Report, FilterState } from '@/types';
|
||||
import { analyticsService } from '@/services/analyticsService';
|
||||
import type { Report, FilterState, HotspotWithSeverity } from '@/types';
|
||||
|
||||
/**
|
||||
* Map page - Interactive map displaying litter reports and cleanup events
|
||||
@@ -10,6 +11,9 @@ export function MapPage() {
|
||||
const [filters, setFilters] = useState<FilterState>({});
|
||||
const [showClusters, setShowClusters] = useState(true);
|
||||
const [showHeatmap, setShowHeatmap] = useState(false);
|
||||
const [showHotspots, setShowHotspots] = useState(false);
|
||||
const [hotspots, setHotspots] = useState<HotspotWithSeverity[]>([]);
|
||||
const [isLoadingHotspots, setIsLoadingHotspots] = useState(false);
|
||||
|
||||
// Sample data for demonstration (will be replaced with API data in later tasks)
|
||||
const sampleReports: Report[] = [
|
||||
@@ -124,6 +128,63 @@ export function MapPage() {
|
||||
setShowHeatmap(!showHeatmap);
|
||||
};
|
||||
|
||||
const handleToggleHotspots = () => {
|
||||
setShowHotspots(!showHotspots);
|
||||
};
|
||||
|
||||
// Fetch hotspots when hotspot view is enabled
|
||||
useEffect(() => {
|
||||
if (showHotspots && hotspots.length === 0) {
|
||||
setIsLoadingHotspots(true);
|
||||
analyticsService.getHotspots()
|
||||
.then((data) => {
|
||||
setHotspots(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed to fetch hotspots:', error);
|
||||
// Use sample hotspot data for demonstration
|
||||
setHotspots([
|
||||
{
|
||||
id: 'hotspot1',
|
||||
latitude: 53.3498,
|
||||
longitude: -6.2603,
|
||||
radius: 500,
|
||||
reportCount: 15,
|
||||
severityScore: 0.75,
|
||||
lastReportDate: new Date('2024-01-20'),
|
||||
calculatedAt: new Date('2024-01-21'),
|
||||
severity: 'high',
|
||||
},
|
||||
{
|
||||
id: 'hotspot2',
|
||||
latitude: 51.8969,
|
||||
longitude: -8.4863,
|
||||
radius: 450,
|
||||
reportCount: 8,
|
||||
severityScore: 0.45,
|
||||
lastReportDate: new Date('2024-01-19'),
|
||||
calculatedAt: new Date('2024-01-21'),
|
||||
severity: 'medium',
|
||||
},
|
||||
{
|
||||
id: 'hotspot3',
|
||||
latitude: 53.2707,
|
||||
longitude: -9.0568,
|
||||
radius: 600,
|
||||
reportCount: 22,
|
||||
severityScore: 0.88,
|
||||
lastReportDate: new Date('2024-01-21'),
|
||||
calculatedAt: new Date('2024-01-21'),
|
||||
severity: 'critical',
|
||||
},
|
||||
]);
|
||||
})
|
||||
.finally(() => {
|
||||
setIsLoadingHotspots(false);
|
||||
});
|
||||
}
|
||||
}, [showHotspots]);
|
||||
|
||||
return (
|
||||
<div className="h-screen flex flex-col">
|
||||
<div className="bg-white border-b border-gray-200 px-4 py-4 sm:px-6 lg:px-8">
|
||||
@@ -137,9 +198,11 @@ export function MapPage() {
|
||||
<div className="h-full bg-white rounded-lg shadow-lg overflow-hidden relative">
|
||||
<MapView
|
||||
reports={sampleReports}
|
||||
hotspots={hotspots}
|
||||
filters={filters}
|
||||
showClusters={showClusters}
|
||||
showHeatmap={showHeatmap}
|
||||
showHotspots={showHotspots}
|
||||
onMarkerClick={handleMarkerClick}
|
||||
onMapClick={handleMapClick}
|
||||
/>
|
||||
@@ -151,6 +214,9 @@ export function MapPage() {
|
||||
showClusters={showClusters}
|
||||
onToggleHeatmap={handleToggleHeatmap}
|
||||
showHeatmap={showHeatmap}
|
||||
onToggleHotspots={handleToggleHotspots}
|
||||
showHotspots={showHotspots}
|
||||
isLoadingHotspots={isLoadingHotspots}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user