Spaces:
Paused
Paused
File size: 2,301 Bytes
025301c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | import { useEffect, useRef } from 'react';
import L from 'leaflet';
export default function MapView({ members, groups, sos }) {
const elRef = useRef(null);
const mapRef = useRef(null);
const markersRef = useRef(new Map());
const didFit = useRef(false);
useEffect(() => {
const map = L.map(elRef.current, { center: [48.8566, 2.3522], zoom: 12 });
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
maxZoom: 19,
}).addTo(map);
mapRef.current = map;
return () => map.remove();
}, []);
useEffect(() => {
const map = mapRef.current;
if (!map) return;
const sosMembers = new Set(sos.filter((a) => a.state !== 'resolved').map((a) => a.member_id));
const colorOf = (gid) => groups.find((g) => g.id === gid)?.color || '#64748b';
const positioned = members.filter((m) => m.lat != null && m.lng != null);
const seen = new Set();
for (const m of positioned) {
seen.add(m.id);
const isSos = sosMembers.has(m.id);
const icon = L.divIcon({
className: 'marker-wrap',
html: `<div class="marker ${m.status} ${isSos ? 'sos' : ''}" style="--c:${colorOf(m.group_id)}"></div>`,
iconSize: [16, 16],
iconAnchor: [8, 8],
});
let mk = markersRef.current.get(m.id);
if (!mk) {
mk = L.marker([m.lat, m.lng], { icon }).addTo(map);
markersRef.current.set(m.id, mk);
} else {
mk.setLatLng([m.lat, m.lng]);
mk.setIcon(icon);
}
mk.bindPopup(
`<b>${m.name}</b>${m.callsign ? ` · ${m.callsign}` : ''}<br/>` +
`${m.group_name || 'no group'} · ${m.status}<br/>` +
`battery ${m.battery != null ? m.battery + '%' : '–'}<br/>` +
`${m.lat.toFixed(5)}, ${m.lng.toFixed(5)}`
);
}
for (const [id, mk] of markersRef.current) {
if (!seen.has(id)) {
map.removeLayer(mk);
markersRef.current.delete(id);
}
}
if (!didFit.current && positioned.length) {
didFit.current = true;
map.fitBounds(L.latLngBounds(positioned.map((m) => [m.lat, m.lng])).pad(0.3));
}
}, [members, groups, sos]);
return <div ref={elRef} className="map" />;
} |