diff --git a/static/compare.js b/static/compare.js
index 9dbb5f9..f795db5 100644
--- a/static/compare.js
+++ b/static/compare.js
@@ -16,6 +16,7 @@ import { getJSON, TTL } from "./cache.js";
import { initFindButton } from "./mappicker.js";
import { MONTHS, pad, isoOfDate, monthStart, monthEnd, buildChunks,
clickOpensPicker } from "./shared.js";
+import { fmtTemp, fmtDelta, onUnitChange } from "./units.js";
const CMP = {
comfort: "thermograph:cmpComfort",
@@ -243,7 +244,8 @@ function computeStats(series) {
// ---- render ----
const pct = (v) => `${v < 10 ? v.toFixed(1) : Math.round(v)}%`;
-const deg = (v) => `${Math.round(v)}°`;
+// Temperature *differences* (avg miss, typical miss) in the active unit.
+const deg = (v) => fmtDelta(v);
function renderLocList() {
locList.innerHTML = locations.map((l, i) => {
@@ -269,7 +271,7 @@ function rankCard(loc, s, rank) {
const stats =
`
` +
`
Colder${pct(s.belowPct)}${s.below ? `avg ${deg(s.avgBelow)} below` : "—"}
` +
- `
In comfort${pct(s.comfortPct)}±${tol}° of ${comfort}°
` +
+ `
In comfort${pct(s.comfortPct)}±${fmtDelta(tol)} of ${fmtTemp(comfort)}
` +
`
Warmer${pct(s.abovePct)}${s.above ? `avg ${deg(s.avgAbove)} above` : "—"}
` +
`
`;
return `` +
@@ -301,8 +303,8 @@ function renderResults() {
const win = scored[0];
const span = `${monthLabel(range.start)} – ${monthLabel(range.end)}`;
const lead = scored.length > 1
- ? `
${win.loc.name} best matches ${comfort}° — ${pct(win.s.comfortPct)} of days within ±${tol}°`
- : `
${win.loc.name}: ${pct(win.s.comfortPct)} of days within ±${tol}° of ${comfort}°`;
+ ? `
${win.loc.name} best matches ${fmtTemp(comfort)} — ${pct(win.s.comfortPct)} of days within ±${fmtDelta(tol)}`
+ : `
${win.loc.name}: ${pct(win.s.comfortPct)} of days within ±${fmtDelta(tol)} of ${fmtTemp(comfort)}`;
head.hidden = false;
head.innerHTML = `
${lead}
` +
`
By ${BASIS_LABEL[basis]} · ${span}${loading ? ` · loading ${loading} more…` : ""}
`;
@@ -335,18 +337,27 @@ locList.addEventListener("click", (e) => {
// Comfort / band / basis: instant re-rank over data already in hand — no refetch.
comfortInput.addEventListener("input", () => {
comfort = +comfortInput.value;
- comfortVal.textContent = `${comfort}°`;
+ comfortVal.textContent = fmtTemp(comfort);
lsSet(CMP.comfort, String(comfort));
writeHashState();
renderResults();
});
tolInput.addEventListener("input", () => {
tol = +tolInput.value;
- tolVal.textContent = `±${tol}°`;
+ tolVal.textContent = `±${fmtDelta(tol)}`;
lsSet(CMP.tol, String(tol));
writeHashState();
renderResults();
});
+
+// The °F/°C toggle only flips what's shown — comfort/tol/series all stay in °F
+// (the API's unit), so there's nothing to refetch or re-rank, just re-render the
+// numbers: the two slider labels and every card.
+onUnitChange(() => {
+ comfortVal.textContent = fmtTemp(comfort);
+ tolVal.textContent = `±${fmtDelta(tol)}`;
+ renderResults();
+});
basisToggle.addEventListener("click", (e) => {
const btn = e.target.closest("button[data-basis]");
if (!btn) return;
@@ -373,8 +384,8 @@ clickOpensPicker(startInput, endInput); // whole-field tap opens the month pic
if (hash.start && hash.end) range = { start: hash.start, end: hash.end };
}
- comfortInput.value = comfort; comfortVal.textContent = `${comfort}°`;
- tolInput.value = tol; tolVal.textContent = `±${tol}°`;
+ comfortInput.value = comfort; comfortVal.textContent = fmtTemp(comfort);
+ tolInput.value = tol; tolVal.textContent = `±${fmtDelta(tol)}`;
basisToggle.querySelectorAll("button").forEach((b) => b.classList.toggle("active", b.dataset.basis === basis));
startInput.value = range.start; endInput.value = range.end;
diff --git a/static/units.js b/static/units.js
index d07b6d8..7e5980d 100644
--- a/static/units.js
+++ b/static/units.js
@@ -19,6 +19,15 @@ export function fmtTemp(vF, withLetter) {
return `${Math.round(toUnit(vF))}°${withLetter ? _unit : ""}`;
}
+// A Fahrenheit-degree *difference* (a span or tolerance, not an absolute
+// reading) formatted in the active unit. Differences scale by 5/9 with no 32°
+// offset, so they can't go through toUnit/fmtTemp.
+export function fmtDelta(dF, withLetter) {
+ if (dF == null || isNaN(dF)) return "—";
+ const d = _unit === "C" ? dF * 5 / 9 : dF;
+ return `${Math.round(d)}°${withLetter ? _unit : ""}`;
+}
+
export function onUnitChange(cb) { _unitCbs.push(cb); }
export function setUnit(u) {
@@ -39,8 +48,7 @@ function syncUnitToggle(wrap) {
}
// Drop a segmented °F/°C control into the header's top-right, ahead of the view
-// switcher. A page opts out with data-no-unit-toggle on (Compare does:
-// its comfort slider is inherently °F-based).
+// switcher. A page opts out with data-no-unit-toggle on .
(function buildUnitToggle() {
const brand = document.querySelector(".brand");
if (!brand || brand.querySelector(".unit-toggle")) return;