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:
parent
86acc56143
commit
29c26dcf1b
@ -1,8 +1,7 @@
|
||||
<script>
|
||||
import { app } from '../lib/stores/app.svelte.js'
|
||||
import { saveSettings } from '../lib/storage/db.js'
|
||||
import { fetchLightningStrikes, projectStrikeToLayer } from '../lib/api/lightning.js'
|
||||
import { filterStrikesWithinKm } from '../lib/api/lightning.js'
|
||||
import { fetchLightningStrikes } from '../lib/api/lightning.js'
|
||||
|
||||
// --- Radar data ---
|
||||
let radarData = $state(null)
|
||||
@ -23,18 +22,13 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
|
||||
|
||||
const loc = $derived(app.selectedLocation)
|
||||
|
||||
// --- Lightning strike layer ---
|
||||
let showLightning = $state(app.settings.showLightning || false)
|
||||
// --- Lightning strikes (fetched for notifications only, never drawn on the map) ---
|
||||
let strikes = $state([])
|
||||
let lightningError = $state('')
|
||||
let lightningLoading = $state(false)
|
||||
let lightningTimer = null
|
||||
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 ---
|
||||
$effect(() => {
|
||||
if (loc) {
|
||||
@ -63,7 +57,7 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
|
||||
|
||||
// --- Lightning layer ---
|
||||
async function loadLightning() {
|
||||
if (!loc || !showLightning) return
|
||||
if (!loc) return
|
||||
lightningLoading = true
|
||||
lightningError = ''
|
||||
try {
|
||||
@ -86,14 +80,6 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
|
||||
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() {
|
||||
stopLightningTimer()
|
||||
lightningTimer = setInterval(loadLightning, LIGHTNING_REFRESH_MS)
|
||||
@ -102,10 +88,9 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
|
||||
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(() => {
|
||||
const active = showLightning && loc
|
||||
if (active) {
|
||||
if (loc) {
|
||||
loadLightning()
|
||||
startLightningTimer()
|
||||
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 ---
|
||||
const pastFrames = $derived(radarData?.radar?.past || [])
|
||||
const nowcastFrames = $derived(radarData?.radar?.nowcast || [])
|
||||
@ -252,18 +228,6 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
|
||||
<div class="radar-section">
|
||||
<div class="radar-title-row">
|
||||
<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>
|
||||
|
||||
{#if error && !loc}
|
||||
@ -311,19 +275,6 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
|
||||
/>
|
||||
{/if}
|
||||
{/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>
|
||||
|
||||
<!-- Location marker (scrolls with map via panX/panY) -->
|
||||
@ -352,20 +303,6 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
|
||||
</div>
|
||||
{/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 -->
|
||||
<div class="zoom-ctrl">
|
||||
@ -436,31 +373,6 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
|
||||
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-err {
|
||||
display: flex;
|
||||
@ -564,40 +476,6 @@ import { filterStrikesWithinKm } from '../lib/api/lightning.js'
|
||||
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 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user