diff --git a/src/plugins/layers/useLightning.js b/src/plugins/layers/useLightning.js index c673c7bc..809e5981 100644 --- a/src/plugins/layers/useLightning.js +++ b/src/plugins/layers/useLightning.js @@ -45,15 +45,17 @@ function lzwDecode(compressed) { } // Haversine formula for distance calculation -function calculateDistance(lat1, lon1, lat2, lon2, unit = 'km') { - const R = unit === 'km' ? 6371.14 : 3963.1; // Earth radius in km or miles +function calculateDistance(lat1, lon1, lat2, lon2) { + // Calculate the distance in both km and miles, returning both + const Rkm = 6371.14; // Earth radius in km + const Rmiles = 3963.1; // Earth radius in miles const dLat = ((lat2 - lat1) * Math.PI) / 180; const dLon = ((lon2 - lon1) * Math.PI) / 180; const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos((lat1 * Math.PI) / 180) * Math.cos((lat2 * Math.PI) / 180) * Math.sin(dLon / 2) * Math.sin(dLon / 2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); - return R * c; + return { km: Rkm * c, miles: Rmiles * c }; } // Strike age colors (fading over time) @@ -65,7 +67,7 @@ function getStrikeColor(ageMinutes) { return '#8B4513'; // Brown (very old, >30 min) } -export function useLayer({ enabled = false, opacity = 0.9, map = null, lowMemoryMode = false }) { +export function useLayer({ enabled = false, opacity = 0.9, map = null, lowMemoryMode = false, allUnits }) { const [strikeMarkers, setStrikeMarkers] = useState([]); const [lightningData, setLightningData] = useState([]); const [statsControl, setStatsControl] = useState(null); @@ -83,6 +85,8 @@ export function useLayer({ enabled = false, opacity = 0.9, map = null, lowMemory const MAX_STRIKES = lowMemoryMode ? 100 : 500; const STRIKE_RETENTION_MS = 1800000; // 30 min + const unitsStr = allUnits.dist === 'metric' ? 'km' : 'miles'; + // Fetch WebSocket key from Blitzortung (fallback to 111) useEffect(() => { if (enabled && !wsKey) { @@ -595,8 +599,8 @@ export function useLayer({ enabled = false, opacity = 0.9, map = null, lowMemory const nearbyNewStrikes = lightningData.filter((strike) => { if (strike.timestamp < ONE_MINUTE_AGO) return false; - const distance = calculateDistance(stationLat, stationLon, strike.lat, strike.lon, 'km'); - return distance <= ALERT_RADIUS_KM; + const distance = calculateDistance(stationLat, stationLon, strike.lat, strike.lon); + return distance.km <= ALERT_RADIUS_KM; }); // Flash the stats panel red if there are nearby strikes @@ -688,8 +692,8 @@ export function useLayer({ enabled = false, opacity = 0.9, map = null, lowMemory const panelWrapper = L.DomUtil.create('div', 'panel-wrapper'); const div = L.DomUtil.create('div', 'lightning-proximity', panelWrapper); - div.innerHTML = - '
📍 Nearby Strikes (30km)
No recent strikes
'; + // Unfortunately, to fit both km and miles in the header we need to override the font size + div.innerHTML = `
📍 Nearby Strikes(30km/18.6miles)
No recent strikes
`; // Prevent map interaction L.DomEvent.disableClickPropagation(div); @@ -832,15 +836,15 @@ export function useLayer({ enabled = false, opacity = 0.9, map = null, lowMemory const distance = calculateDistance(stationLat, stationLon, strike.lat, strike.lon, 'km'); return { ...strike, distance }; }) - .filter((strike) => strike.distance <= PROXIMITY_RADIUS_KM) - .sort((a, b) => a.distance - b.distance); // Sort by distance (closest first) + .filter((strike) => strike.distance.km <= PROXIMITY_RADIUS_KM) + .sort((a, b) => a.distance.km - b.distance.km); // Sort by distance (closest first) let contentHTML = ''; if (nearbyStrikes.length === 0) { contentHTML = `
- ✅ No strikes within 30km
+ ✅ No strikes within 30km (18.6 miles)
All clear
`; @@ -849,6 +853,8 @@ export function useLayer({ enabled = false, opacity = 0.9, map = null, lowMemory const ageMinutes = Math.floor((now - closestStrike.timestamp) / 60000); const ageSeconds = Math.floor((now - closestStrike.timestamp) / 1000); const ageStr = ageMinutes > 0 ? `${ageMinutes}m ago` : `${ageSeconds}s ago`; + const closestStrikeDistance = + allUnits.dist === 'metric' ? closestStrike.distance.km : closestStrike.distance.miles; contentHTML = `
@@ -856,7 +862,7 @@ export function useLayer({ enabled = false, opacity = 0.9, map = null, lowMemory ⚡ ${nearbyStrikes.length} strike${nearbyStrikes.length > 1 ? 's' : ''} detected
- Closest: ${closestStrike.distance.toFixed(1)} km
+ Closest: ${closestStrikeDistance.toFixed(1)} ${unitsStr}
Time: ${ageStr}
Polarity: ${closestStrike.polarity === 'positive' ? '+' : '-'} ${Math.round(closestStrike.intensity)} kA
@@ -869,9 +875,10 @@ export function useLayer({ enabled = false, opacity = 0.9, map = null, lowMemory .map((strike, idx) => { const age = Math.floor((now - strike.timestamp) / 1000); const timeStr = age < 60 ? `${age}s` : `${Math.floor(age / 60)}m`; + const dist = (allUnits.dist === 'metric' ? strike.distance.km : strike.distance.miles).toFixed(1); return `
- ${idx + 1}. ${strike.distance.toFixed(1)} km • ${timeStr} • ${strike.polarity === 'positive' ? '+' : '-'}${Math.round(strike.intensity)} kA + ${idx + 1}. ${dist} ${unitsStr} • ${timeStr} • ${strike.polarity === 'positive' ? '+' : '-'}${Math.round(strike.intensity)} kA
`; })