feat: trace-chart viewer comfort (Tier 1) — collapse-gaps x-axis (optional continuous), zoom/pan/cursor-sync #103
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Follow-on to #101 (trace charts, first cut). The shipped viewer is the deliberately-naive
cut: static line / overlay / panels on uPlot defaults. This is the "Tier 1" comfort pass
named in the web-viewer effort estimate — the cheap, high-leverage jump that makes the
served page feel like a chart rather than a screenshot — plus the one explicitly-requested
data-model change: the x-axis should not be continuous by default.
The whole feature lives in
crates/aura-cli/assets/chart-viewer.js(purebuildCharts+browser-only
mount) and a little page chrome incrates/aura-cli/src/render.rs(
CHART_HEAD/ CSS). The Rust serve contract (build_chart_data,render_chart_html,ColumnarTrace/TraceStore) is unchanged:window.AURA_TRACESalready carriesxs(real timestamps) + per-series points; the new behaviour is purely how the viewer maps them.
X-axis: collapse gaps by default, continuous optional
Today the x-axis plots against the real union timestamps (
scales.x.time=false,data[0]=xs), so non-trading time (nights, weekends) shows as proportional horizontalblanks. Requested: the x-axis should not be continuous (or only optionally).
Decision (derived, recorded here): add an ordinal x-mode and make it the default;
keep continuous as a one-click toggle in the page.
data[0] = [0,1,…,n-1](every slot evenly spaced → gaps collapse); the x-axistick
valuesand the legend x-readout map the index back to the realxs[i]value.data[0] = xs(today's behaviour), reachable via an in-page toggle.Rationale for an in-page toggle over a CLI flag: the broader goal is a more comfortable
viewer, and a live toggle lets you compare both spacings without regenerating the page; it
also keeps the injected payload and the whole Rust side untouched (the choice is client-side).
Default ordinal honours the primary clause ("should not be continuous"); continuous is the
"(or only optional)" fallback.
Pretty date/time axis labels (epoch→
HH:MM, session-aware ticks) are deliberately out ofscope here — they need the timestamp unit / instrument context (manifest /
Aura.toml),which is the #102 / Tier-3 "session-aware axis" strand. Ordinal mode here shows the raw
xs[i]on hover; no epoch assumption (the synthetic demos use small-integer timestamps).Tier 1 interaction comfort
over-wheel handler; not in uPlot core).xs[i]).cursor.synckey so the vertical crosshair linesup across stacked panels (panels mode).
Acceptance
flips to continuous and back, both modes rendering the same series.
buildCharts(traces, mode, xMode)stays pure + headless-guardable: a node guard assertsordinal
data[0]is the index array with an xvaluesformatter, continuousdata[0]isxs, and null gaps are still preserved verbatim (the existing gap guard must stay green).<script src>; uPlot + data inlined).Lineage: #101 (first cut), C22 (playground = trace explorer), the Tier-1 row of the web-viewer
effort estimate. Not the deferred families/comparison (C21) or the
aura servebackend.Design decisions (specify, spec 0057) — derived forks
Recording the load-bearing forks this spec decides, beyond the ordinal/continuous
default already in the issue body. All are derived calls (rationale below), not user
decisions — vetoable.
Fork: interaction gestures (drag vs box-zoom). The body listed both "drag box-zoom"
and "drag-pan" — contradictory, since drag is one gesture. → Resolved: drag = pan,
wheel = zoom (x, cursor-anchored), double-click = reset. uPlot's default drag-box-zoom
is overridden in favour of drag-pan. Basis (derived): the acceptance already says "drag
pans" / "double-click restores the full range", and drag-pan is the TradingView-comfort
norm this Tier-1 pass targets; box-zoom is the less idiomatic gesture and is dropped
rather than bound to a modifier (keep the naive viewer simple).
Fork: ordinal-mode axis/readout label. → Resolved: show the raw
xs[i]timestampvalue, no epoch→date formatting. Basis (derived): the synthetic demos use small-integer
timestamps, so
new Date(x)would render 1970 nonsense; honest date formatting needs thetimestamp unit / instrument context (manifest /
Aura.toml), which is the #102 / Tier-3"session-aware axis" strand, explicitly out of this cut's scope.
Fork: toggle granularity. → Resolved: one global x-mode toggle re-renders all charts
(overlay's single chart, or every panel) in the same mode. Basis (derived): a per-chart
toggle would let panels drift out of x-alignment, contradicting the timestamp-aligned-panels
contract from #101; global keeps panels coherent and the control simple.
Fork: cursor-sync scope. → Resolved: panels share a uPlot
cursor.synckey so thecrosshair lines up across stacked panels; overlay is a single chart and needs none. Basis
(derived): sync is only meaningful across multiple charts (panels mode); overlay already
superimposes on one chart.