feat(radar): stop rendering lightning strikes on the map

Lightning strikes are now fetched but no longer drawn on the map or
controlled by a toggle. The periodic fetch is retained so the app can
drive strike notifications. Removes the toggle button, strike markers,
status banner, and their CSS.

Net -122 lines.
This commit is contained in:
hermes-explorigin 2026-09-20 21:44:28 +00:00
parent 86acc56143
commit 29c26dcf1b

View File

@ -1,8 +1,7 @@
<script> <script>
import { app } from '../lib/stores/app.svelte.js' import { app } from '../lib/stores/app.svelte.js'
import { saveSettings } from '../lib/storage/db.js' import { saveSettings } from '../lib/storage/db.js'
import { fetchLightningStrikes, projectStrikeToLayer } from '../lib/api/lightning.js' import { fetchLightningStrikes } from '../lib/api/lightning.js'
import { filterStrikesWithinKm } from '../lib/api/lightning.js'
// --- Radar data --- // --- Radar data ---
let radarData = $state(null) let radarData = $state(null)
@ -23,18 +22,13 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
const loc = $derived(app.selectedLocation) const loc = $derived(app.selectedLocation)
// --- Lightning strike layer --- // --- Lightning strikes (fetched for notifications only, never drawn on the map) ---
let showLightning = $state(app.settings.showLightning || false)
let strikes = $state([]) let strikes = $state([])
let lightningError = $state('') let lightningError = $state('')
let lightningLoading = $state(false) let lightningLoading = $state(false)
let lightningTimer = null let lightningTimer = null
const LIGHTNING_REFRESH_MS = 30_000 const LIGHTNING_REFRESH_MS = 30_000
// 25 miles is the max distance a lightning strike is worth showing.
const MILES_TO_KM = 1.609344
const LIGHTNING_VIEW_RADIUS_KM = 25 * MILES_TO_KM
// --- Load radar metadata --- // --- Load radar metadata ---
$effect(() => { $effect(() => {
if (loc) { if (loc) {
@ -63,7 +57,7 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
// --- Lightning layer --- // --- Lightning layer ---
async function loadLightning() { async function loadLightning() {
if (!loc || !showLightning) return if (!loc) return
lightningLoading = true lightningLoading = true
lightningError = '' lightningError = ''
try { try {
@ -86,14 +80,6 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
lightningLoading = false lightningLoading = false
} }
} }
function toggleLightning() {
showLightning = !showLightning
// Persist the preference; the $effect below drives fetching/timing.
app.settings = { ...app.settings, showLightning }
saveSettings({ ...app.settings, alertThresholds: { ...app.settings.alertThresholds } }).catch(() => {})
}
function startLightningTimer() { function startLightningTimer() {
stopLightningTimer() stopLightningTimer()
lightningTimer = setInterval(loadLightning, LIGHTNING_REFRESH_MS) lightningTimer = setInterval(loadLightning, LIGHTNING_REFRESH_MS)
@ -102,10 +88,9 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
if (lightningTimer) { clearInterval(lightningTimer); lightningTimer = null } if (lightningTimer) { clearInterval(lightningTimer); lightningTimer = null }
} }
// Re-fetch lightning when the selected location or the layer's data source changes. // Re-fetch lightning whenever the selected location or data source changes (notifications).
$effect(() => { $effect(() => {
const active = showLightning && loc if (loc) {
if (active) {
loadLightning() loadLightning()
startLightningTimer() startLightningTimer()
return () => { stopLightningTimer() } return () => { stopLightningTimer() }
@ -116,15 +101,6 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
} }
}) })
const strikeMarkers = $derived(
showLightning
? filterStrikesWithinKm(strikes, loc.lat, loc.lon, LIGHTNING_VIEW_RADIUS_KM).map((s) => ({
...s,
...projectStrikeToLayer(s.lat, s.lon, { zoom, cx, cy, tileSize: TILE_SIZE }),
}))
: []
)
// --- Frame data --- // --- Frame data ---
const pastFrames = $derived(radarData?.radar?.past || []) const pastFrames = $derived(radarData?.radar?.past || [])
const nowcastFrames = $derived(radarData?.radar?.nowcast || []) const nowcastFrames = $derived(radarData?.radar?.nowcast || [])
@ -252,18 +228,6 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
<div class="radar-section"> <div class="radar-section">
<div class="radar-title-row"> <div class="radar-title-row">
<h3 class="section-title">Precipitation Radar</h3> <h3 class="section-title">Precipitation Radar</h3>
{#if loc}
<button
class="layer-toggle"
class:on={showLightning}
onclick={toggleLightning}
role="switch"
aria-checked={showLightning}
title="Toggle lightning strike layer"
>
⚡ Lightning
</button>
{/if}
</div> </div>
{#if error && !loc} {#if error && !loc}
@ -311,19 +275,6 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
/> />
{/if} {/if}
{/each} {/each}
<!-- Lightning strike markers (pan/zoom with the map) -->
{#if showLightning}
<div class="lightning-layer" aria-label="Lightning strikes">
{#each strikeMarkers as s (s.time + '_' + s.lat + '_' + s.lon)}
<span
class="lightning-strike"
title={'Strike ' + new Date(s.time * 1000).toLocaleString()}
style="left: {s.x}px; top: {s.y}px"
></span>
{/each}
</div>
{/if}
</div> </div>
<!-- Location marker (scrolls with map via panX/panY) --> <!-- Location marker (scrolls with map via panX/panY) -->
@ -352,20 +303,6 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
</div> </div>
{/if} {/if}
<!-- Lightning layer status -->
{#if showLightning && lightningLoading}
<div class="lightning-status">
<span class="text-xs">⏳ Loading lightning...</span>
</div>
{:else if showLightning && lightningError}
<div class="lightning-status lightning-status-err">
<span class="text-xs">⚡ {lightningError} (relay not live yet)</span>
</div>
{:else if showLightning && strikes.length === 0 && !lightningLoading}
<div class="lightning-status">
<span class="text-xs">⚡ No recent strikes nearby</span>
</div>
{/if}
<!-- Zoom controls --> <!-- Zoom controls -->
<div class="zoom-ctrl"> <div class="zoom-ctrl">
@ -436,31 +373,6 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
gap: 8px; gap: 8px;
} }
.layer-toggle {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 5px 11px;
font-size: 0.78rem;
font-weight: 600;
border-radius: 16px;
border: 1px solid var(--color-border);
background: var(--color-surface);
color: var(--color-text-muted);
cursor: pointer;
margin-bottom: 12px;
transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.layer-toggle:hover {
border-color: var(--color-primary);
color: var(--color-text);
}
.layer-toggle.on {
background: rgba(250, 204, 21, 0.18);
border-color: #facc15;
color: #fde047;
}
.radar-status, .radar-status,
.radar-status-err { .radar-status-err {
display: flex; display: flex;
@ -564,40 +476,6 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
z-index: 1; z-index: 1;
} }
/* ── Lightning strike layer ── */
.lightning-layer {
position: absolute;
inset: 0;
z-index: 2;
pointer-events: none;
}
.lightning-strike {
position: absolute;
width: 8px;
height: 8px;
margin-left: -4px;
margin-top: -4px;
border-radius: 50%;
background: #facc15;
box-shadow: 0 0 6px 2px rgba(250, 204, 21, 0.85);
pointer-events: auto;
}
.lightning-status {
position: absolute;
top: 12px;
right: 12px;
z-index: 10;
padding: 5px 10px;
background: rgba(10, 22, 40, 0.8);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
pointer-events: none;
}
.lightning-status-err {
border-color: rgba(239, 68, 68, 0.4);
}
/* ── Location marker ── */ /* ── Location marker ── */
.location-marker { .location-marker {