---
name: lit-svg-metric-chart
description: Make a Lit inline-SVG stacked-area/time-series chart metric-aware (toggle chips + axis formatters) without a charting library
---
# Lit Inline-SVG Metric Chart
## When to use
- A Lit view renders a hand-rolled inline-`<svg>` chart (stacked area, line, or bars) and you need to let users switch the plotted metric (e.g. tokens vs cost vs requests) without adding a charting dependency.
- A chart only plots one hard-coded field and the underlying series object already carries multiple numeric fields per point.
- Axis labels are missing, distorted, or unreadable (clipped edges, stretched text, wrong number formatting for the metric).
## How to apply
1. **Add metric state, not a reload path.** Put the selected metric on the controller state (e.g. `metric: "tokens"`) with a setter (`setCreditsMetric`) that only re-reads the *already-fetched* series and re-renders. Do NOT refetch from the gateway on metric switch — the data is already present per-point.
2. **Parameterize the renderer.** Change `renderChart(points)` → `renderChart(points, metric, bucket)`. Add a `metricValue(seriesEntry, metric)` helper that selects the field; never index the raw field name inline.
3. **Per-metric axis formatters.** Y-axis ticks pick a formatter by metric: `compact()` for counts (tokens/requests), `usd()` for currency. X-axis: derive ~6 evenly-spaced ticks via a `fmtBucketTick(t, bucket)` helper keyed on bucket granularity (`minute`→`HH:MM`, `hour`→`HH:00`, `day`/`week`→`MMM D`); anchor first/middle/last so edge labels don't clip.
4. **Toggle chips in the section header.** Render a chip row (TOKENS / COST / REQUESTS) wired to the setter; mark the active one with an `.active` class. Reuse the existing chip CSS class rather than inventing new styles.
5. **Fix SVG distortion.** Remove `preserveAspectRatio="none"` (it stretches text) and reserve vertical space with a `labelPad` so axis labels fit; bump `height` if labels still crowd the plot.
6. **Dynamic title** from state: `"<metric> by <groupBy>"`.
7. **Companion table for the new dimension** (optional): if you added a groupBy like `model`, add a `renderTopModels()` table mirroring the existing `renderProviderTable` structure and `.cr-table` / `.cr-empty` styling.
8. **Build to verify** (`npm run build` from `ui/`). Watch the working directory — a prior `cd ui` means re-running with a `ui/`-prefixed path fails on the path, not the build.
## Rules
- Never add a charting library when the existing chart is hand-rolled inline SVG — extend it.
- Never refetch on metric toggle; the series already holds every metric per point.
- Always select the plotted field through a single `metricValue()` helper, never a hard-coded field reference scattered in the render path.
- Always match metric to its number formatter (counts vs currency) on both axis and tables.
- Always reuse existing CSS classes (`.cr-chip`, `.cr-table`, `.cr-empty`) and sibling render functions as the structural template.
- Never leave `preserveAspectRatio="none"` on a chart that renders text labels.