Settings: one window for how far back every graph reaches, 1 minute to 24 hours

Each machine keeps 300 points per curve whatever the window, so memory doesn't follow it;
a wider window means wider points, each the average of its bucket rather than one instant
out of it. The hub passes the setting to every machine it manages.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-09-20 19:07:55 -07:00
co-authored by Claude Opus 5
parent 885b050d02
commit 04dd98e2cd
13 changed files with 533 additions and 33 deletions
+44
View File
@@ -21,6 +21,50 @@ export function setRefreshMs(ms: number) {
export function fmtMs(ms: number): string { return ms >= 1000 ? `${ms / 1000} s` : `${ms} ms` }
// ---- how far back the graphs reach ----
// Unlike the refresh rate this is the machine's own setting, not a look: the hub keeps the
// window and pushes it to every machine, so the graphs of any of them reach equally far back.
// The value is cached here only so a page can draw before the hub has answered.
export const HISTORY_OPTIONS = [60, 300, 600, 1800, 3600, 3 * 3600, 6 * 3600, 12 * 3600, 24 * 3600] as const
export const DEFAULT_HISTORY_SEC = 600
export const HISTORY_POINTS = 300 // what a machine keeps per curve, whatever the window
const HKEY = 'hamlab.historySec'
export function getHistorySec(): number {
const v = Number(localStorage.getItem(HKEY))
return v >= 60 && v <= 86400 ? v : DEFAULT_HISTORY_SEC
}
export function setHistorySec(sec: number) {
if (!(sec >= 60 && sec <= 86400)) return
localStorage.setItem(HKEY, String(sec))
window.dispatchEvent(new CustomEvent('hamlab:history', { detail: sec }))
}
// useHistorySec re-renders the caller when the window changes.
export function useHistorySec(): number {
const [sec, setSec] = useState(getHistorySec())
useEffect(() => {
const h = (e: Event) => setSec((e as CustomEvent<number>).detail)
window.addEventListener('hamlab:history', h)
return () => window.removeEventListener('hamlab:history', h)
}, [])
return sec
}
// How far apart the kept points are: the refresh rate until the window is wider than
// HISTORY_POINTS of it, then the window split that many ways. Mirrors the server.
export function strideMs(windowSec: number, refreshMs: number): number {
return Math.max(refreshMs, Math.round((windowSec * 1000) / HISTORY_POINTS))
}
export function fmtWindowSec(sec: number): string {
if (sec >= 3600) { const h = sec / 3600; return `${Number.isInteger(h) ? h : h.toFixed(1)} hour${h === 1 ? '' : 's'}` }
if (sec >= 60) { const m = sec / 60; return `${Number.isInteger(m) ? m : m.toFixed(1)} min` }
return `${Math.round(sec)} s`
}
// useRefreshMs re-renders the caller when the global rate changes.
export function useRefreshMs(floor = 0): number {
const [ms, setMs] = useState(getRefreshMs())