fix(weather-ca): paint HRDPS cells at 0.5° size, not HRRR's 0.125°

The canvas overlay hard-coded a 0.0625° half-step when projecting each
cell to canvas pixels — correct for HRRR (0.125° native grid) but wrong
for HRDPS, which we downsample to 0.5° (0.25° half-step). At HRRR's
half-step every HRDPS cell got painted at 1/16th its actual area, so
the overlay over Canada looked like a sparse pinstripe of vertical
streaks instead of contiguous coverage.

Plumb halfStep through the WeatherCanvasOverlay constructor and pick
0.25 vs 0.0625 in the hook based on data-source.
This commit is contained in:
Graham McIntire 2026-04-30 12:34:24 -05:00
parent 47031e17f1
commit fe7d998f67
No known key found for this signature in database
GPG key ID: F4ABF488E6029E59

View file

@ -475,7 +475,7 @@ function buildPaintScale(layerId: LayerId): PaintScale | BoolPaintScale | null {
// SVG overlay — at low zoom (whole-CONUS, ~80k cells) SVG paint cost // SVG overlay — at low zoom (whole-CONUS, ~80k cells) SVG paint cost
// dominated; canvas is one fillRect per cell with a precomputed LUT. // dominated; canvas is one fillRect per cell with a precomputed LUT.
const WeatherCanvasOverlayProto: L.LayerOptions & { const WeatherCanvasOverlayProto: L.LayerOptions & {
initialize: (this: WeatherCanvasOverlay, pack: CellPack | null, layerId: LayerId) => void initialize: (this: WeatherCanvasOverlay, pack: CellPack | null, layerId: LayerId, halfStep: number) => void
onAdd: (this: WeatherCanvasOverlay, map: L.Map) => WeatherCanvasOverlay onAdd: (this: WeatherCanvasOverlay, map: L.Map) => WeatherCanvasOverlay
onRemove: (this: WeatherCanvasOverlay, map: L.Map) => WeatherCanvasOverlay onRemove: (this: WeatherCanvasOverlay, map: L.Map) => WeatherCanvasOverlay
setPack: (this: WeatherCanvasOverlay, pack: CellPack | null) => void setPack: (this: WeatherCanvasOverlay, pack: CellPack | null) => void
@ -483,9 +483,10 @@ const WeatherCanvasOverlayProto: L.LayerOptions & {
_reset: (this: WeatherCanvasOverlay) => void _reset: (this: WeatherCanvasOverlay) => void
_draw: (this: WeatherCanvasOverlay) => void _draw: (this: WeatherCanvasOverlay) => void
} = { } = {
initialize(pack: CellPack | null, layerId: LayerId): void { initialize(pack: CellPack | null, layerId: LayerId, halfStep: number): void {
this.pack = pack this.pack = pack
this.layerId = layerId this.layerId = layerId
this.halfStep = halfStep
}, },
onAdd(map: L.Map): WeatherCanvasOverlay { onAdd(map: L.Map): WeatherCanvasOverlay {
this._map = map this._map = map
@ -537,7 +538,7 @@ const WeatherCanvasOverlayProto: L.LayerOptions & {
if (!paintScale) return if (!paintScale) return
const map = this._map const map = this._map
const halfStep = 0.0625 const halfStep = this.halfStep
const lats = this.pack.lats const lats = this.pack.lats
const lons = this.pack.lons const lons = this.pack.lons
const n = this.pack.cellCount const n = this.pack.cellCount
@ -578,6 +579,7 @@ const WeatherCanvasOverlayProto: L.LayerOptions & {
interface WeatherCanvasOverlay extends L.Layer { interface WeatherCanvasOverlay extends L.Layer {
pack: CellPack | null pack: CellPack | null
layerId: LayerId layerId: LayerId
halfStep: number
_map: L.Map _map: L.Map
_canvas: HTMLCanvasElement _canvas: HTMLCanvasElement
setPack(pack: CellPack | null): void setPack(pack: CellPack | null): void
@ -585,7 +587,7 @@ interface WeatherCanvasOverlay extends L.Layer {
} }
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const WeatherCanvasOverlayCtor: new (pack: CellPack | null, layerId: LayerId) => WeatherCanvasOverlay = (L.Layer as any).extend(WeatherCanvasOverlayProto) const WeatherCanvasOverlayCtor: new (pack: CellPack | null, layerId: LayerId, halfStep: number) => WeatherCanvasOverlay = (L.Layer as any).extend(WeatherCanvasOverlayProto)
function buildDetailHTML(point: WeatherPoint): string { function buildDetailHTML(point: WeatherPoint): string {
if (!point) return "" if (!point) return ""
@ -1050,7 +1052,12 @@ export const WeatherMap: WeatherMapHook = {
} }
if (!this.weatherOverlay) { if (!this.weatherOverlay) {
this.weatherOverlay = new WeatherCanvasOverlayCtor(this.pack, this.selectedLayer) // HRRR is on a 0.125° native grid → 0.0625 half-step.
// HRDPS in this app is downsampled to 0.5° → 0.25 half-step.
// Without this, HRDPS cells were painted 1/16th their actual area
// and looked like a sparse pinstripe instead of an overlay.
const halfStep = this.source === "hrdps" ? 0.25 : 0.0625
this.weatherOverlay = new WeatherCanvasOverlayCtor(this.pack, this.selectedLayer, halfStep)
this.weatherOverlay.addTo(this.map) this.weatherOverlay.addTo(this.map)
} else { } else {
this.weatherOverlay.pack = this.pack this.weatherOverlay.pack = this.pack