From bf8c6d4789a0018314b408d8726ee19ba702416c Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Fri, 3 Apr 2026 16:54:13 -0500 Subject: [PATCH] Add color scales and detail panel entries for upper-air weather layers --- assets/js/weather_map_hook.js | 140 +++++++++++++++++++++++++++++++--- 1 file changed, 131 insertions(+), 9 deletions(-) diff --git a/assets/js/weather_map_hook.js b/assets/js/weather_map_hook.js index 06ebacff..8b08807e 100644 --- a/assets/js/weather_map_hook.js +++ b/assets/js/weather_map_hook.js @@ -71,6 +71,114 @@ const COLOR_SCALES = { format: v => v ? "Yes" : "No", label: "Ducting Detected", unit: "" + }, + surface_rh: { + breakpoints: [ + { value: 0, r: 255, g: 144, b: 68 }, + { value: 30, r: 255, g: 229, b: 102 }, + { value: 60, r: 125, g: 255, b: 212 }, + { value: 80, r: 0, g: 255, b: 163 }, + { value: 100, r: 0, g: 200, b: 130 } + ], + format: v => v != null ? `${v.toFixed(0)}%` : "N/A", + label: "Relative Humidity", + unit: "%" + }, + surface_refractivity: { + breakpoints: [ + { value: 250, r: 255, g: 79, b: 79 }, + { value: 300, r: 255, g: 144, b: 68 }, + { value: 330, r: 255, g: 229, b: 102 }, + { value: 360, r: 125, g: 255, b: 212 }, + { value: 400, r: 0, g: 255, b: 163 } + ], + format: v => v != null ? `${v.toFixed(1)} N` : "N/A", + label: "Surface Refractivity", + unit: "N" + }, + temp_850mb: { + breakpoints: [ + { value: -20, r: 0, g: 0, b: 200 }, + { value: -5, r: 100, g: 149, b: 237 }, + { value: 5, r: 255, g: 255, b: 150 }, + { value: 15, r: 255, g: 140, b: 0 }, + { value: 30, r: 200, g: 0, b: 0 } + ], + format: v => v != null ? `${v.toFixed(1)} °C` : "N/A", + label: "Temperature at 850mb", + unit: "°C" + }, + dewpoint_850mb: { + breakpoints: [ + { value: -20, r: 139, g: 90, b: 43 }, + { value: -5, r: 194, g: 165, b: 116 }, + { value: 5, r: 173, g: 216, b: 230 }, + { value: 15, r: 65, g: 105, b: 225 }, + { value: 25, r: 0, g: 0, b: 180 } + ], + format: v => v != null ? `${v.toFixed(1)} °C` : "N/A", + label: "Dewpoint at 850mb", + unit: "°C" + }, + lapse_rate: { + breakpoints: [ + { value: 0, r: 0, g: 255, b: 163 }, + { value: 4, r: 125, g: 255, b: 212 }, + { value: 6.5, r: 255, g: 229, b: 102 }, + { value: 8, r: 255, g: 144, b: 68 }, + { value: 10, r: 255, g: 79, b: 79 } + ], + format: v => v != null ? `${v.toFixed(1)} °C/km` : "N/A", + label: "Lapse Rate", + unit: "°C/km" + }, + inversion_strength: { + breakpoints: [ + { value: 0, r: 80, g: 80, b: 80 }, + { value: 1, r: 255, g: 229, b: 102 }, + { value: 3, r: 125, g: 255, b: 212 }, + { value: 5, r: 0, g: 255, b: 163 }, + { value: 10, r: 0, g: 200, b: 130 } + ], + format: v => v != null ? (v > 0 ? `+${v.toFixed(1)} °C` : "None") : "N/A", + label: "Inversion Strength", + unit: "°C" + }, + inversion_base_m: { + breakpoints: [ + { value: 0, r: 0, g: 255, b: 163 }, + { value: 500, r: 125, g: 255, b: 212 }, + { value: 1000, r: 255, g: 229, b: 102 }, + { value: 2000, r: 255, g: 144, b: 68 }, + { value: 3000, r: 255, g: 79, b: 79 } + ], + format: v => v != null ? `${v.toFixed(0)} m AGL` : "None", + label: "Inversion Base Height", + unit: "m" + }, + duct_base_m: { + breakpoints: [ + { value: 0, r: 0, g: 255, b: 163 }, + { value: 200, r: 125, g: 255, b: 212 }, + { value: 500, r: 255, g: 229, b: 102 }, + { value: 1000, r: 255, g: 144, b: 68 }, + { value: 2000, r: 255, g: 79, b: 79 } + ], + format: v => v != null ? `${v.toFixed(0)} m AGL` : "None", + label: "Duct Base Height", + unit: "m" + }, + duct_strength: { + breakpoints: [ + { value: 0, r: 80, g: 80, b: 80 }, + { value: 5, r: 255, g: 229, b: 102 }, + { value: 10, r: 125, g: 255, b: 212 }, + { value: 20, r: 0, g: 255, b: 163 }, + { value: 40, r: 0, g: 200, b: 130 } + ], + format: v => v != null ? (v > 0 ? `${v.toFixed(1)} M-units` : "None") : "N/A", + label: "Duct Strength", + unit: "M" } } @@ -99,12 +207,23 @@ function buildDetailHTML(point) { const rows = [ { label: "Temperature", value: COLOR_SCALES.temperature.format(point.temperature), color: "#ff9044" }, - { label: "Dewpoint Depression", value: COLOR_SCALES.dewpoint_depression.format(point.dewpoint_depression), color: "#7dffd4" }, - { label: "Boundary Layer", value: COLOR_SCALES.bl_height.format(point.bl_height), color: "#ffe566" }, - { label: "Precipitable Water", value: COLOR_SCALES.pwat.format(point.pwat), color: "#4169e1" }, - { label: "Refractivity Gradient", value: COLOR_SCALES.refractivity_gradient.format(point.refractivity_gradient), color: "#00ffa3" }, - { label: "Ducting Detected", value: COLOR_SCALES.ducting.format(point.ducting), color: point.ducting ? "#00ffa3" : "#ff4f4f" }, - { label: "Surface Pressure", value: point.surface_pressure_mb != null ? `${point.surface_pressure_mb.toFixed(1)} mb` : "N/A", color: "#aaa" } + { label: "Td Depression", value: COLOR_SCALES.dewpoint_depression.format(point.dewpoint_depression), color: "#7dffd4" }, + { label: "Rel. Humidity", value: COLOR_SCALES.surface_rh.format(point.surface_rh), color: "#00ffa3" }, + { label: "Sfc Pressure", value: point.surface_pressure_mb != null ? `${point.surface_pressure_mb.toFixed(1)} mb` : "N/A", color: "#aaa" }, + { label: "Refractivity", value: COLOR_SCALES.surface_refractivity.format(point.surface_refractivity), color: "#00ffa3" }, + { label: "N-Gradient", value: COLOR_SCALES.refractivity_gradient.format(point.refractivity_gradient), color: "#00ffa3" }, + { label: "BL Height", value: COLOR_SCALES.bl_height.format(point.bl_height), color: "#ffe566" }, + { label: "PWAT", value: COLOR_SCALES.pwat.format(point.pwat), color: "#4169e1" }, + { separator: true }, + { label: "T @ 850mb", value: COLOR_SCALES.temp_850mb.format(point.temp_850mb), color: "#ff9044" }, + { label: "Td @ 850mb", value: COLOR_SCALES.dewpoint_850mb.format(point.dewpoint_850mb), color: "#4169e1" }, + { label: "Lapse Rate", value: COLOR_SCALES.lapse_rate.format(point.lapse_rate), color: "#ffe566" }, + { label: "Inversion", value: COLOR_SCALES.inversion_strength.format(point.inversion_strength), color: point.inversion_strength > 0 ? "#00ffa3" : "#666" }, + { label: "Inv. Base", value: COLOR_SCALES.inversion_base_m.format(point.inversion_base_m), color: point.inversion_base_m != null ? "#7dffd4" : "#666" }, + { separator: true }, + { label: "Ducting", value: COLOR_SCALES.ducting.format(point.ducting), color: point.ducting ? "#00ffa3" : "#ff4f4f" }, + { label: "Duct Base", value: COLOR_SCALES.duct_base_m.format(point.duct_base_m), color: point.duct_base_m != null ? "#00ffa3" : "#666" }, + { label: "Duct Strength", value: COLOR_SCALES.duct_strength.format(point.duct_strength), color: point.duct_strength != null ? "#00ffa3" : "#666" } ] const mobile = isMobile() @@ -115,12 +234,15 @@ function buildDetailHTML(point) { ? `
` : "" - const tableRows = rows.map(r => - ` + const tableRows = rows.map(r => { + if (r.separator) { + return `
` + } + return ` \u25cf ${r.label} ${r.value} ` - ).join("") + }).join("") const time = point.valid_time ? new Date(point.valid_time).toISOString().replace("T", " ").slice(0, 16) + " UTC"