diff --git a/client/src/pages/MapView.jsx b/client/src/pages/MapView.jsx
index 5bae316..c6185dd 100644
--- a/client/src/pages/MapView.jsx
+++ b/client/src/pages/MapView.jsx
@@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react';
import { MapContainer, TileLayer, Marker, Popup, Circle, useMap } from 'react-leaflet';
import { Icon } from 'leaflet';
+import L from 'leaflet'; // For divIcon and other Leaflet utilities
import { useSocket } from '../contexts/SocketContext';
import api from '../services/api';
import { format } from 'date-fns';
@@ -310,75 +311,157 @@ const MapView = () => {
})}
{/* RSSI-based Detection Rings around Detectors */}
- {showDroneDetections && droneDetectionHistory
- .filter(detection => {
- const hasCoords = detection.geo_lat && detection.geo_lon;
- console.log('MapView: Filtering detection:', detection, 'hasCoords:', hasCoords);
- return hasCoords;
- })
- .map(detection => {
- console.log('MapView: Rendering ring for detection:', detection);
- const opacity = getDetectionOpacity(detection);
- const age = getDetectionAge(detection);
- console.log('MapView: Detection age:', age, 'opacity:', opacity);
-
- // Calculate ring radius based on RSSI (rough distance estimation)
- const getRssiRadius = (rssi) => {
- if (rssi > -40) return 100; // <100m - very close
- if (rssi > -60) return 500; // ~500m - close
- if (rssi > -70) return 1500; // ~1.5km - medium
- if (rssi > -80) return 4000; // ~4km - far
- if (rssi > -90) return 8000; // ~8km - very far
- return 15000; // ~15km - maximum range
- };
+ {showDroneDetections && (() => {
+ const filteredDetections = droneDetectionHistory
+ .filter(detection => {
+ const hasCoords = detection.geo_lat && detection.geo_lon;
+ console.log('MapView: Filtering detection:', detection, 'hasCoords:', hasCoords);
+ return hasCoords;
+ });
- const radius = getRssiRadius(detection.rssi);
- console.log('MapView: Ring radius:', radius, 'for RSSI:', detection.rssi);
-
- // Color based on threat level and RSSI strength
- const getRingColor = (rssi, droneType) => {
- // Orlan drones (type 1) always red
- if (droneType === 1) return '#dc2626'; // red-600
+ // Group detections by detector position to handle multiple drones at same detector
+ const detectionsByDetector = filteredDetections.reduce((acc, detection) => {
+ const key = `${detection.geo_lat}_${detection.geo_lon}`;
+ if (!acc[key]) acc[key] = [];
+ acc[key].push(detection);
+ return acc;
+ }, {});
+
+ return Object.entries(detectionsByDetector).flatMap(([detectorKey, detections]) => {
+ return detections.map((detection, droneIndex) => {
+ console.log('MapView: Rendering ring for detection:', detection, 'droneIndex:', droneIndex, 'totalDrones:', detections.length);
+ const opacity = getDetectionOpacity(detection);
+ const age = getDetectionAge(detection);
+ console.log('MapView: Detection age:', age, 'opacity:', opacity);
- // Other drones based on RSSI
- if (rssi > -60) return '#dc2626'; // red-600 - close
- if (rssi > -70) return '#ea580c'; // orange-600 - medium
- return '#16a34a'; // green-600 - far
- };
+ // Calculate ring radius based on RSSI (rough distance estimation)
+ const getRssiRadius = (rssi) => {
+ if (rssi > -40) return 100; // <100m - very close
+ if (rssi > -60) return 500; // ~500m - close
+ if (rssi > -70) return 1500; // ~1.5km - medium
+ if (rssi > -80) return 4000; // ~4km - far
+ if (rssi > -90) return 8000; // ~8km - very far
+ return 15000; // ~15km - maximum range
+ };
- const ringColor = getRingColor(detection.rssi, detection.drone_type);
-
- return (
-