Fix jwt-token
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { MapContainer, TileLayer, Marker, Popup, Circle, useMap } from 'react-leaflet';
|
import { MapContainer, TileLayer, Marker, Popup, Circle, useMap } from 'react-leaflet';
|
||||||
import { Icon } from 'leaflet';
|
import { Icon } from 'leaflet';
|
||||||
|
import L from 'leaflet'; // For divIcon and other Leaflet utilities
|
||||||
import { useSocket } from '../contexts/SocketContext';
|
import { useSocket } from '../contexts/SocketContext';
|
||||||
import api from '../services/api';
|
import api from '../services/api';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
@@ -310,14 +311,25 @@ const MapView = () => {
|
|||||||
})}
|
})}
|
||||||
|
|
||||||
{/* RSSI-based Detection Rings around Detectors */}
|
{/* RSSI-based Detection Rings around Detectors */}
|
||||||
{showDroneDetections && droneDetectionHistory
|
{showDroneDetections && (() => {
|
||||||
|
const filteredDetections = droneDetectionHistory
|
||||||
.filter(detection => {
|
.filter(detection => {
|
||||||
const hasCoords = detection.geo_lat && detection.geo_lon;
|
const hasCoords = detection.geo_lat && detection.geo_lon;
|
||||||
console.log('MapView: Filtering detection:', detection, 'hasCoords:', hasCoords);
|
console.log('MapView: Filtering detection:', detection, 'hasCoords:', hasCoords);
|
||||||
return hasCoords;
|
return hasCoords;
|
||||||
})
|
});
|
||||||
.map(detection => {
|
|
||||||
console.log('MapView: Rendering ring for detection:', detection);
|
// 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 opacity = getDetectionOpacity(detection);
|
||||||
const age = getDetectionAge(detection);
|
const age = getDetectionAge(detection);
|
||||||
console.log('MapView: Detection age:', age, 'opacity:', opacity);
|
console.log('MapView: Detection age:', age, 'opacity:', opacity);
|
||||||
@@ -348,24 +360,93 @@ const MapView = () => {
|
|||||||
|
|
||||||
const ringColor = getRingColor(detection.rssi, detection.drone_type);
|
const ringColor = getRingColor(detection.rssi, detection.drone_type);
|
||||||
|
|
||||||
|
// Different visual styles for multiple drones at same detector
|
||||||
|
const getDashPattern = (droneType, droneIndex, totalDrones) => {
|
||||||
|
if (droneType === 1) return null; // Orlan always solid
|
||||||
|
|
||||||
|
if (totalDrones === 1) return '5, 5'; // Single drone - normal dashed
|
||||||
|
|
||||||
|
// Multiple drones - different dash patterns
|
||||||
|
const patterns = [
|
||||||
|
'5, 5', // Standard dashed
|
||||||
|
'10, 3, 3, 3', // Long dash, dot, dot
|
||||||
|
'15, 5', // Long dashes
|
||||||
|
'3, 3', // Short dashes
|
||||||
|
'8, 3, 3, 3, 3, 3' // Complex pattern
|
||||||
|
];
|
||||||
|
return patterns[droneIndex % patterns.length];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Slight offset for multiple rings to make them more visible
|
||||||
|
const getPositionOffset = (droneIndex, totalDrones) => {
|
||||||
|
if (totalDrones === 1) return [0, 0];
|
||||||
|
|
||||||
|
const offsetDistance = 0.0001; // Very small offset in degrees
|
||||||
|
const angle = (droneIndex * 360 / totalDrones) * (Math.PI / 180);
|
||||||
|
return [
|
||||||
|
Math.cos(angle) * offsetDistance,
|
||||||
|
Math.sin(angle) * offsetDistance
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
const totalDrones = detections.length;
|
||||||
|
const dashPattern = getDashPattern(detection.drone_type, droneIndex, totalDrones);
|
||||||
|
const [latOffset, lonOffset] = getPositionOffset(droneIndex, totalDrones);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={detection.id}>
|
<React.Fragment key={`${detection.id}_${droneIndex}`}>
|
||||||
{/* Detection Ring around Detector (NOT drone position) */}
|
{/* Detection Ring around Detector (NOT drone position) */}
|
||||||
<Circle
|
<Circle
|
||||||
center={[detection.geo_lat, detection.geo_lon]} // Detector position
|
center={[
|
||||||
|
detection.geo_lat + latOffset,
|
||||||
|
detection.geo_lon + lonOffset
|
||||||
|
]} // Detector position with slight offset
|
||||||
radius={radius}
|
radius={radius}
|
||||||
pathOptions={{
|
pathOptions={{
|
||||||
color: ringColor,
|
color: ringColor,
|
||||||
fillColor: ringColor,
|
fillColor: ringColor,
|
||||||
fillOpacity: 0.05 * opacity,
|
fillOpacity: totalDrones > 1 ? 0.02 * opacity : 0.05 * opacity, // Less fill for multiple
|
||||||
weight: detection.drone_type === 1 ? 3 : 2, // Thicker for Orlan
|
weight: detection.drone_type === 1 ? 3 : (totalDrones > 1 ? 3 : 2), // Thicker for multiple or Orlan
|
||||||
opacity: opacity * 0.8,
|
opacity: opacity * 0.8,
|
||||||
dashArray: detection.drone_type === 1 ? null : '5, 5' // Solid for Orlan, dashed for others
|
dashArray: dashPattern
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Optional: Small info marker at detector showing detection details */}
|
{/* Drone ID label for multiple drones */}
|
||||||
{age < 1 && ( // Only show for very recent detections (< 1 minute)
|
{totalDrones > 1 && age < 5 && ( // Show labels for recent detections with multiple drones
|
||||||
|
<Marker
|
||||||
|
position={[
|
||||||
|
detection.geo_lat + (latOffset * 3),
|
||||||
|
detection.geo_lon + (lonOffset * 3)
|
||||||
|
]}
|
||||||
|
icon={L.divIcon({
|
||||||
|
html: `<div style="
|
||||||
|
background: ${ringColor};
|
||||||
|
color: white;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.3);
|
||||||
|
white-space: nowrap;
|
||||||
|
">
|
||||||
|
${detection.drone_id || `D${droneIndex + 1}`}
|
||||||
|
</div>`,
|
||||||
|
className: 'drone-id-label',
|
||||||
|
iconSize: [30, 16],
|
||||||
|
iconAnchor: [15, 8]
|
||||||
|
})}
|
||||||
|
opacity={opacity * 0.9}
|
||||||
|
>
|
||||||
|
<Popup>
|
||||||
|
<DroneDetectionPopup detection={detection} age={age} droneTypes={droneTypes} />
|
||||||
|
</Popup>
|
||||||
|
</Marker>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Optional: Small info marker at detector showing detection details (for single drone) */}
|
||||||
|
{totalDrones === 1 && age < 1 && ( // Only show for very recent detections (< 1 minute) and single drone
|
||||||
<Marker
|
<Marker
|
||||||
position={[detection.geo_lat, detection.geo_lon]}
|
position={[detection.geo_lat, detection.geo_lon]}
|
||||||
icon={createDroneIcon(detection.rssi, detection.drone_type)}
|
icon={createDroneIcon(detection.rssi, detection.drone_type)}
|
||||||
@@ -378,7 +459,9 @@ const MapView = () => {
|
|||||||
)}
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
})}
|
});
|
||||||
|
});
|
||||||
|
})()}
|
||||||
</MapContainer>
|
</MapContainer>
|
||||||
|
|
||||||
{/* Map Legend - Fixed positioning and visibility */}
|
{/* Map Legend - Fixed positioning and visibility */}
|
||||||
@@ -419,6 +502,12 @@ const MapView = () => {
|
|||||||
<div className="w-3 h-3 border-2 border-green-500 rounded-full bg-green-500 bg-opacity-10"></div>
|
<div className="w-3 h-3 border-2 border-green-500 rounded-full bg-green-500 bg-opacity-10"></div>
|
||||||
<span className="text-gray-700">Far Range (<-70dBm)</span>
|
<span className="text-gray-700">Far Range (<-70dBm)</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="border-t border-gray-200 mt-2 pt-2">
|
||||||
|
<div className="text-xs text-gray-600 mb-1">Multiple Drones:</div>
|
||||||
|
<div className="text-xs text-gray-500 mb-1">• Different dash patterns</div>
|
||||||
|
<div className="text-xs text-gray-500 mb-1">• Drone ID labels shown</div>
|
||||||
|
<div className="text-xs text-gray-500 mb-1">• Slight position offsets</div>
|
||||||
|
</div>
|
||||||
<div className="text-xs text-gray-500 mt-2">
|
<div className="text-xs text-gray-500 mt-2">
|
||||||
Ring size = estimated distance from detector
|
Ring size = estimated distance from detector
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user