diff --git a/client/src/pages/MapView.jsx b/client/src/pages/MapView.jsx index adeba89..23976b6 100644 --- a/client/src/pages/MapView.jsx +++ b/client/src/pages/MapView.jsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import { MapContainer, TileLayer, Marker, Popup, Circle } from 'react-leaflet'; +import { MapContainer, TileLayer, Marker, Popup, Circle, useMap } from 'react-leaflet'; import { Icon } from 'leaflet'; import { useSocket } from '../contexts/SocketContext'; import api from '../services/api'; @@ -24,6 +24,19 @@ Icon.Default.mergeOptions({ shadowUrl, }); +// Component to handle dynamic map bounds +const FitBounds = ({ bounds }) => { + const map = useMap(); + + useEffect(() => { + if (bounds && bounds.length === 2) { + map.fitBounds(bounds, { padding: [20, 20] }); + } + }, [bounds, map]); + + return null; +}; + // Custom icons const createDeviceIcon = (status, hasDetections) => { let color = '#6b7280'; // gray for offline/inactive @@ -73,8 +86,9 @@ const MapView = () => { const [devices, setDevices] = useState([]); const [selectedDevice, setSelectedDevice] = useState(null); const [loading, setLoading] = useState(true); - const [mapCenter, setMapCenter] = useState([59.4, 18.1]); // Stockholm area center - const [mapZoom, setMapZoom] = useState(11); // Closer zoom for Stockholm area + const [mapCenter, setMapCenter] = useState([59.3293, 18.0686]); // Default to Stockholm center + const [mapZoom, setMapZoom] = useState(10); // Default zoom level + const [mapBounds, setMapBounds] = useState(null); const [showDroneDetections, setShowDroneDetections] = useState(true); const [droneDetectionHistory, setDroneDetectionHistory] = useState([]); const { recentDetections, deviceStatus } = useSocket(); @@ -131,15 +145,31 @@ const MapView = () => { setDevices(deviceData); - // Set map bounds to Stockholm area with all three detectors - if (deviceData.length > 0 && devices.length === 0) { - // Stockholm area bounds that include Arlanda, Naval Base, and Royal Castle - const stockholmBounds = [ - [59.2, 17.8], // Southwest - [59.7, 18.4] // Northeast + // Calculate bounds dynamically based on device locations + if (deviceData.length > 0) { + const lats = deviceData.map(device => device.geo_lat); + const lons = deviceData.map(device => device.geo_lon); + + const minLat = Math.min(...lats); + const maxLat = Math.max(...lats); + const minLon = Math.min(...lons); + const maxLon = Math.max(...lons); + + // Add padding around the bounds (10% on each side) + const latPadding = (maxLat - minLat) * 0.1; + const lonPadding = (maxLon - minLon) * 0.1; + + const bounds = [ + [minLat - latPadding, minLon - lonPadding], // Southwest + [maxLat + latPadding, maxLon + lonPadding] // Northeast ]; - setMapCenter([59.4, 18.1]); // Center of Stockholm area - setMapZoom(11); + + setMapBounds(bounds); + + // Set center to the middle of all devices + const centerLat = (minLat + maxLat) / 2; + const centerLon = (minLon + maxLon) / 2; + setMapCenter([centerLat, centerLon]); } } catch (error) { console.error('Error fetching devices:', error); @@ -220,15 +250,8 @@ const MapView = () => { center={mapCenter} zoom={mapZoom} className="h-full w-full" - whenCreated={(map) => { - // Set bounds to Stockholm area to show all three detectors - const stockholmBounds = [ - [59.2, 17.8], // Southwest - [59.7, 18.4] // Northeast - ]; - map.fitBounds(stockholmBounds, { padding: [20, 20] }); - }} > +