fix(contacts/map): align line colors with sidebar legend
The polylines were sourcing from --band-* CSS vars (a separate, theme-aware design palette) while the legend swatches rendered from the Elixir @band_colors map, so the two diverged for every band — e.g. 10 GHz showed lime on the map and emerald in the legend. Emit `data-band-color` on each band checkbox and have the JS hook read from there, making the legend the single source of truth. Drops the now-redundant theme observer / restyleLines plumbing.
This commit is contained in:
parent
90cc554c4f
commit
18680b35e5
2 changed files with 13 additions and 58 deletions
|
|
@ -40,7 +40,6 @@ interface ContactsMapHook extends ViewHook {
|
||||||
map: L.Map
|
map: L.Map
|
||||||
delegatedChange: (e: Event) => void
|
delegatedChange: (e: Event) => void
|
||||||
delegatedClick: (e: Event) => void
|
delegatedClick: (e: Event) => void
|
||||||
themeObserver: MutationObserver | null
|
|
||||||
initMap(this: ContactsMapHook): void
|
initMap(this: ContactsMapHook): void
|
||||||
buildLines(this: ContactsMapHook): void
|
buildLines(this: ContactsMapHook): void
|
||||||
syncBandLayers(this: ContactsMapHook): void
|
syncBandLayers(this: ContactsMapHook): void
|
||||||
|
|
@ -49,7 +48,6 @@ interface ContactsMapHook extends ViewHook {
|
||||||
updateCount(this: ContactsMapHook, count: number): void
|
updateCount(this: ContactsMapHook, count: number): void
|
||||||
wireControls(this: ContactsMapHook): void
|
wireControls(this: ContactsMapHook): void
|
||||||
unwireControls(this: ContactsMapHook): void
|
unwireControls(this: ContactsMapHook): void
|
||||||
restyleLines(this: ContactsMapHook): void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function inDateRange(tsDate: string, startDate: string, endDate: string): boolean {
|
function inDateRange(tsDate: string, startDate: string, endDate: string): boolean {
|
||||||
|
|
@ -60,48 +58,26 @@ function inDateRange(tsDate: string, startDate: string, endDate: string): boolea
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Amateur-band palette. Nine of these map to the design system's --band-*
|
// Band colors are sourced from the legend swatches in the sidebar — each
|
||||||
// CSS vars (defined in assets/css/app.css); the higher mm-wave bands above
|
// band checkbox carries `data-band-color` set server-side from
|
||||||
// 47 GHz fall back to hard-coded hues since the design set only spans up
|
// `Microwaveprop.ContactMapLive`'s @band_colors map. Reading from the DOM
|
||||||
// to 6mm. CSS vars are resolved once per page via getComputedStyle because
|
// keeps the legend the single source of truth: change the Elixir map and
|
||||||
// Leaflet writes the color onto the SVG `stroke` attribute, which does not
|
// both the swatch and the polyline update in lockstep.
|
||||||
// evaluate `var()` references.
|
|
||||||
const BAND_VAR: Record<number, string> = {
|
|
||||||
1296: "--band-23cm",
|
|
||||||
2304: "--band-13cm",
|
|
||||||
3400: "--band-9cm",
|
|
||||||
5760: "--band-6cm",
|
|
||||||
10000: "--band-3cm",
|
|
||||||
24000: "--band-1-25cm",
|
|
||||||
47000: "--band-6mm",
|
|
||||||
}
|
|
||||||
|
|
||||||
const BAND_FALLBACK: Record<number, string> = {
|
|
||||||
68000: "#dc2626",
|
|
||||||
75000: "#c026d3",
|
|
||||||
122000: "#db2777",
|
|
||||||
134000: "#e11d48",
|
|
||||||
241000: "#b91c1c",
|
|
||||||
}
|
|
||||||
|
|
||||||
let BAND_COLORS: Record<number, string> | null = null
|
let BAND_COLORS: Record<number, string> | null = null
|
||||||
|
|
||||||
function resolveBandColors(): Record<number, string> {
|
function resolveBandColors(): Record<number, string> {
|
||||||
if (BAND_COLORS) return BAND_COLORS
|
if (BAND_COLORS) return BAND_COLORS
|
||||||
const styles = getComputedStyle(document.documentElement)
|
const resolved: Record<number, string> = {}
|
||||||
const resolved: Record<number, string> = { ...BAND_FALLBACK }
|
const inputs = document.querySelectorAll<HTMLInputElement>("input[data-band][data-band-color]")
|
||||||
for (const [band, cssVar] of Object.entries(BAND_VAR)) {
|
for (const inp of inputs) {
|
||||||
const value = styles.getPropertyValue(cssVar).trim()
|
const band = parseInt(inp.dataset.band || "", 10)
|
||||||
if (value) resolved[Number(band)] = value
|
const color = inp.dataset.bandColor
|
||||||
|
if (Number.isFinite(band) && color) resolved[band] = color
|
||||||
}
|
}
|
||||||
BAND_COLORS = resolved
|
BAND_COLORS = resolved
|
||||||
return resolved
|
return resolved
|
||||||
}
|
}
|
||||||
|
|
||||||
function invalidateBandColors(): void {
|
|
||||||
BAND_COLORS = null
|
|
||||||
}
|
|
||||||
|
|
||||||
function bandLabel(mhz: number): string {
|
function bandLabel(mhz: number): string {
|
||||||
if (mhz >= 1000) {
|
if (mhz >= 1000) {
|
||||||
const ghz = mhz / 1000
|
const ghz = mhz / 1000
|
||||||
|
|
@ -125,7 +101,6 @@ export const ContactsMap = {
|
||||||
this.bandGroups = new Map()
|
this.bandGroups = new Map()
|
||||||
this.lines = []
|
this.lines = []
|
||||||
this.dotLayer = L.layerGroup()
|
this.dotLayer = L.layerGroup()
|
||||||
this.themeObserver = null
|
|
||||||
|
|
||||||
// Callsign filter still roundtrips through LiveView (debounced) — it's
|
// Callsign filter still roundtrips through LiveView (debounced) — it's
|
||||||
// cross-cutting and fires rarely. Band toggles are purely client-side.
|
// cross-cutting and fires rarely. Band toggles are purely client-side.
|
||||||
|
|
@ -144,18 +119,6 @@ export const ContactsMap = {
|
||||||
|
|
||||||
this.wireControls()
|
this.wireControls()
|
||||||
|
|
||||||
// Re-color polylines when the theme toggles. Leaflet writes `stroke` as
|
|
||||||
// an SVG attribute (which does not resolve CSS vars), so we re-read the
|
|
||||||
// resolved --band-* values and call setStyle on each line.
|
|
||||||
this.themeObserver = new MutationObserver(() => {
|
|
||||||
invalidateBandColors()
|
|
||||||
this.restyleLines()
|
|
||||||
})
|
|
||||||
this.themeObserver.observe(document.documentElement, {
|
|
||||||
attributes: true,
|
|
||||||
attributeFilter: ["data-theme"]
|
|
||||||
})
|
|
||||||
|
|
||||||
requestAnimationFrame(() => this.initMap())
|
requestAnimationFrame(() => this.initMap())
|
||||||
|
|
||||||
fetch(fetchUrl)
|
fetch(fetchUrl)
|
||||||
|
|
@ -174,16 +137,6 @@ export const ContactsMap = {
|
||||||
|
|
||||||
destroyed(this: ContactsMapHook) {
|
destroyed(this: ContactsMapHook) {
|
||||||
this.unwireControls()
|
this.unwireControls()
|
||||||
if (this.themeObserver) {
|
|
||||||
this.themeObserver.disconnect()
|
|
||||||
this.themeObserver = null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
restyleLines(this: ContactsMapHook) {
|
|
||||||
for (const entry of this.lines) {
|
|
||||||
entry.line.setStyle({ color: bandColor(entry.band) })
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
wireControls(this: ContactsMapHook) {
|
wireControls(this: ContactsMapHook) {
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,7 @@ defmodule MicrowavepropWeb.ContactMapLive do
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked
|
checked
|
||||||
data-band={band}
|
data-band={band}
|
||||||
|
data-band-color={band_color(band)}
|
||||||
style={"accent-color:#{band_color(band)}"}
|
style={"accent-color:#{band_color(band)}"}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
|
|
@ -325,6 +326,7 @@ defmodule MicrowavepropWeb.ContactMapLive do
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked
|
checked
|
||||||
data-band={band}
|
data-band={band}
|
||||||
|
data-band-color={band_color(band)}
|
||||||
style={"accent-color:#{band_color(band)}"}
|
style={"accent-color:#{band_color(band)}"}
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue