Add grid squares and weather radar toggles to the weather map
Ports the same two overlay toggles from /map to /weather: - Maidenhead grid squares via the shared updateGridOverlay helper, redrawn on moveend when visible. - ECCC GeoMet WMS radar (CONUS + Canada dBZ), lazy-created on first toggle with a 6-minute tile refresh timer. Both toggles live in the desktop sidebar below the layer description and in the mobile pulldown panel. Hook cleanup clears the radar refresh timer on destroyed().
This commit is contained in:
parent
2afaeb56a3
commit
2b323189d0
2 changed files with 130 additions and 2 deletions
|
|
@ -1,5 +1,7 @@
|
|||
// assets/js/weather_map_hook.ts
|
||||
|
||||
import { updateGridOverlay } from "./maidenhead_grid"
|
||||
|
||||
// --- Type definitions ---
|
||||
|
||||
interface RGB {
|
||||
|
|
@ -79,6 +81,10 @@ interface WeatherMapHook extends ViewHook {
|
|||
escHint: HTMLDivElement
|
||||
clickMarker: L.LayerGroup
|
||||
legend: L.Control
|
||||
gridLayer: L.LayerGroup
|
||||
gridVisible: boolean
|
||||
radarLayer: L.TileLayer.WMS | null
|
||||
radarRefreshTimer: ReturnType<typeof setInterval> | null
|
||||
_escHandler: (e: KeyboardEvent) => void
|
||||
_layerObserver: MutationObserver
|
||||
|
||||
|
|
@ -438,8 +444,62 @@ export const WeatherMap: WeatherMapHook = {
|
|||
L.DomEvent.disableScrollPropagation(controls)
|
||||
}
|
||||
|
||||
// Maidenhead grid overlay
|
||||
this.gridLayer = L.layerGroup()
|
||||
this.gridVisible = false
|
||||
|
||||
this.handleEvent("toggle_grid", ({ visible }: { visible: boolean }) => {
|
||||
this.gridVisible = visible
|
||||
if (visible) {
|
||||
this.gridLayer.addTo(this.map)
|
||||
updateGridOverlay(this.map, this.gridLayer)
|
||||
} else {
|
||||
this.gridLayer.remove()
|
||||
}
|
||||
})
|
||||
|
||||
// Weather radar overlay (ECCC GeoMet WMS — CONUS + Canada composite dBZ).
|
||||
// Lazy-created on first toggle so we don't hit the service until asked.
|
||||
this.radarLayer = null
|
||||
this.radarRefreshTimer = null
|
||||
|
||||
this.handleEvent("toggle_radar", ({ visible }: { visible: boolean }) => {
|
||||
if (visible) {
|
||||
if (!this.radarLayer) {
|
||||
this.radarLayer = L.tileLayer.wms("https://geo.weather.gc.ca/geomet", {
|
||||
layers: "Radar_1km_dBZ-Extrapolation",
|
||||
format: "image/png",
|
||||
transparent: true,
|
||||
opacity: 0.55,
|
||||
version: "1.3.0",
|
||||
attribution: "Radar © Environment and Climate Change Canada"
|
||||
})
|
||||
}
|
||||
this.radarLayer.addTo(this.map)
|
||||
// ECCC radar updates every ~6 minutes; force a tile refresh on that
|
||||
// cadence so the overlay stays current without a page reload.
|
||||
this.radarRefreshTimer = setInterval(() => {
|
||||
if (this.radarLayer) {
|
||||
// @ts-expect-error setParams exists on WMS TileLayer but isn't in @types/leaflet yet
|
||||
this.radarLayer.setParams({ _: Date.now() })
|
||||
}
|
||||
}, 6 * 60 * 1000)
|
||||
} else {
|
||||
if (this.radarLayer) this.radarLayer.remove()
|
||||
if (this.radarRefreshTimer) {
|
||||
clearInterval(this.radarRefreshTimer)
|
||||
this.radarRefreshTimer = null
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
requestAnimationFrame(() => this.sendBounds())
|
||||
this.map.on("moveend", () => this.sendBounds())
|
||||
this.map.on("moveend", () => {
|
||||
this.sendBounds()
|
||||
if (this.gridVisible) {
|
||||
updateGridOverlay(this.map, this.gridLayer)
|
||||
}
|
||||
})
|
||||
|
||||
this._layerObserver = new MutationObserver(() => {
|
||||
const newLayer = this.el.dataset.selectedLayer as LayerId | undefined
|
||||
|
|
@ -458,6 +518,7 @@ export const WeatherMap: WeatherMapHook = {
|
|||
destroyed(this: WeatherMapHook) {
|
||||
if (this._layerObserver) this._layerObserver.disconnect()
|
||||
if (this._escHandler) document.removeEventListener("keydown", this._escHandler)
|
||||
if (this.radarRefreshTimer) clearInterval(this.radarRefreshTimer)
|
||||
},
|
||||
|
||||
sendBounds(this: WeatherMapHook) {
|
||||
|
|
|
|||
|
|
@ -153,7 +153,9 @@ defmodule MicrowavepropWeb.WeatherMapLive do
|
|||
initial_data_json: Jason.encode!(data),
|
||||
valid_time: valid_time,
|
||||
initial_utc_clock: Calendar.strftime(DateTime.utc_now(), "%H:%M UTC"),
|
||||
bounds: @initial_bounds
|
||||
bounds: @initial_bounds,
|
||||
grid_visible: false,
|
||||
radar_visible: false
|
||||
)}
|
||||
end
|
||||
|
||||
|
|
@ -162,6 +164,28 @@ defmodule MicrowavepropWeb.WeatherMapLive do
|
|||
{:noreply, assign(socket, :selected_layer, layer_id)}
|
||||
end
|
||||
|
||||
def handle_event("toggle_grid", _params, socket) do
|
||||
visible = !socket.assigns.grid_visible
|
||||
|
||||
socket =
|
||||
socket
|
||||
|> assign(:grid_visible, visible)
|
||||
|> push_event("toggle_grid", %{visible: visible})
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_event("toggle_radar", _params, socket) do
|
||||
visible = !socket.assigns.radar_visible
|
||||
|
||||
socket =
|
||||
socket
|
||||
|> assign(:radar_visible, visible)
|
||||
|> push_event("toggle_radar", %{visible: visible})
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_event("map_bounds", bounds, socket) do
|
||||
data = Weather.latest_weather_grid(bounds)
|
||||
|
||||
|
|
@ -296,6 +320,27 @@ defmodule MicrowavepropWeb.WeatherMapLive do
|
|||
{layer_description(@layers, @selected_layer)}
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1 border-t border-base-300 pt-2">
|
||||
<label class="flex items-center gap-2 cursor-pointer px-1">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="toggle toggle-sm toggle-primary"
|
||||
checked={@grid_visible}
|
||||
phx-click="toggle_grid"
|
||||
/>
|
||||
<span class="text-sm">Grid squares</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer px-1">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="toggle toggle-sm toggle-primary"
|
||||
checked={@radar_visible}
|
||||
phx-click="toggle_radar"
|
||||
/>
|
||||
<span class="text-sm">Weather radar</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1 border-t border-base-300 pt-2">
|
||||
<.link navigate="/map" class="btn btn-xs btn-ghost justify-start">
|
||||
Propagation Map
|
||||
|
|
@ -415,6 +460,28 @@ defmodule MicrowavepropWeb.WeatherMapLive do
|
|||
{layer_description(@layers, @selected_layer)}
|
||||
</div>
|
||||
|
||||
<%!-- Overlay toggles --%>
|
||||
<div class="flex flex-col gap-1 border-t border-base-300 pt-2">
|
||||
<label class="flex items-center gap-2 cursor-pointer px-1">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="toggle toggle-sm toggle-primary"
|
||||
checked={@grid_visible}
|
||||
phx-click="toggle_grid"
|
||||
/>
|
||||
<span class="text-sm">Grid squares</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer px-1">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="toggle toggle-sm toggle-primary"
|
||||
checked={@radar_visible}
|
||||
phx-click="toggle_radar"
|
||||
/>
|
||||
<span class="text-sm">Weather radar</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<%!-- Navigation --%>
|
||||
<ul class="menu menu-xs border-t border-base-300 pt-2 px-0">
|
||||
<li>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue