Dashboards, Charts, and Polling
Use dashboards, charts, and polling with the current published Askr packages.
@askrjs/askr0.0.59
How to use dashboards, charts, and polling
Poll through a cancellable query, retain the last successful rows while refreshing, and give the plot stable row identity and an accessible label.
- Import the published @askrjs/askr entrypoint.
- Keep dashboards, charts, and polling configuration next to the component, route, or server composition root that owns it.
- Handle pending, unavailable, cancellation, and failure states, then verify the production path.
import { createPlot } from '@askrjs/charts';
const Plot = createPlot<MetricRow>();
<Plot.Root data={metrics()} rowKey={(row) => row.timestamp} label="Request rate">
<Plot.Axis axis="x" />
<Plot.Axis axis="y" />
<Plot.Line x="timestamp" y="requests" />
</Plot.Root>Goal and architecture
Charts come from `@askrjs/charts`, a typed Canvas 2D plotting library with an immutable scene also available for SVG and data export — there's no separate headless/themed split here, `createPlot<Row>()` is the one entry point. A dashboard combines that with `@askrjs/askr/data`'s query layer for live numbers and `invalidateOnInterval()` for polling, so the chart re-renders whenever its backing query refetches rather than on its own timer.
Implementation
Call `createPlot<RevenueRow>()` once at module scope to get a typed namespace, then compose marks inside `<RevenuePlot.Root data={...} rowKey="id" label="...">` — `Bar`, `Line`, and `Point` marks reference row fields by name, and the type system rejects a numeric channel bound to a string field. For live data, wrap the query driving the chart with `invalidateOnInterval({ ... })` so it refetches on a schedule, and remember to import `@askrjs/charts/styles` once at the app boundary since the structural and theme-token CSS ships separately from the JS. Import `@askrjs/charts/styles` from a CSS file, not a `.ts`/`.tsx` module — it's a CSS export, not a typed module.
Failure states
A polling query that errors mid-interval shouldn't tear down the chart and replace it with an error state on every failed poll — treat a transient poll failure differently from the query's initial load failure, or a flaky network turns a dashboard into a strobe light. Mixing primitives from two different `createPlot()` factories inside one `Root` is a type error by design, not a runtime footgun, so if you hit it the fix is consolidating on one factory per row shape rather than working around the types. Empty data (zero rows) should render an explicit empty state inside `Root`'s children, since an empty canvas with no rows looks identical to a still-loading one.
Verification
Watch a polling-driven chart across several interval ticks and confirm it actually updates when the underlying data changes, not just on first load — it's easy to wire `invalidateOnInterval` to the wrong query key and have the chart look live while it's actually static. Resize the container and confirm the plot redraws correctly rather than clipping, since Canvas-backed charts don't get free reflow the way DOM/SVG ones sometimes do. Finally check the page under a throttled connection to confirm polling backs off or queues sensibly rather than piling up overlapping requests.