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>
|
<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 {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user