Line Chart API
Everything you need to wire up a line chart in code; for the story and demos, see the Line Chart demo.
Import
import "@michi-vz/wc/line-chart";
// <michi-vz-line-chart> is now definedimport { mountLineChart } from "@michi-vz/core";
const chart = mountLineChart(el, props);Props
| Prop | Type | Default | Description |
|---|---|---|---|
timeline | boolean | TimelinePeriodConfig | - | Opt-in "play through years" (cumulative): the marks draw UP TO the active period and extend as the timeline steps; `interpolate` sweeps smoothly between years, `false` jump-cuts. Headless controller via `chart.timeline()` plus the built-in play button + scrubber. Off by default; wins over `progressiveDraw` when both are set. |
dataSet* | LineDataItem[] | - | Array of line series, each with its own points |
title | string | - | Optional chart title rendered above the plot |
yAxisDomain | [number | null, number | null] | - | Fix the y-axis range as [min, max] instead of deriving it from the data. Either bound may be null to keep just that bound data-derived — e.g. [0, null] pins the baseline at 0 while the maximum keeps following the visible (post legend-toggle, post top-N) series. |
yAxisScale | "linear" | "log" | "linear" | Y-axis scale: "linear" (default) or a base-10 "log" scale. In "log" mode, a non-positive value (<= 0) can't be plotted, so those points are dropped as missing (reported via `onDataWarning`); a dataSet with no positive values at all renders the no-data state instead. |
xAxisDataType | "date_annual" | "date_monthly" | "number" | "number" | How x values are parsed and formatted: yearly dates, monthly dates, or plain numbers |
xAxisFormat | (d: number | string) => string | - | Formats an x tick value into its display label |
yAxisFormat | (d: number | string) => string | - | Formats a y tick value into its display label |
ticks | number | 5 | Approximate number of x-axis ticks to generate |
yTicks | number | - | Number of y-axis ticks (default 10, matching the legacy denser value axis). |
showGridLines | boolean | - | Draw horizontal dashed grid lines at each y tick (default true). |
showVerticalGridLines | boolean | - | Draw vertical dashed grid lines at each x tick (default false - the legacy chart drew none). |
highlightZeroLine | boolean | - | Emphasise the y=0 grid line with a darker solid stroke (default true). |
tickValues | Array<number | Date> | - | Explicit tick values, overriding the generated ones |
fillPeriodTicks | boolean | - | Draw a tick for EVERY period across the axis range (every month/year), not just the periods present in the data. Periods with no value render faded and show `noDataTickTooltip` on hover. Opt-in; default false. |
noDataTickTooltip | (date: number) => string | - | Tooltip content (plain text or sanitized HTML) for a faded no-data tick; receives the tick's epoch-ms value. Used only with `fillPeriodTicks`. Default: a localized "Data not available". |
noDataTickColor | string | - | Colour for faded no-data tick labels; sets the `--michi-vz-tick-nodata` CSS var on the host. Used only with `fillPeriodTicks`. |
curve | "curveBumpX" | "curveLinear" | "curveMonotoneX" | - | Default interpolation for every series (per-series `curve` wins). |
detectGaps | boolean | false | Auto-derive `certainty` from missing periods (dashes the gap segment). |
expectedStep | number | - | Expected cadence in axis units; REQUIRED for xAxisDataType "number". |
showDataPoints | boolean | false | Whether to draw a marker at each data point (default false) |
enableMouseLine | boolean | MouseLineConfig | true | Solid vertical crosshair line snapped to the nearest data point x on hover; pass a config object to style it (default true) |
zoom | boolean | LineZoomConfig | - | Opt-in x-axis drag-to-zoom: drag a horizontal range inside the plot to zoom into it (a selection rectangle previews the range). Marks clip to the plot box; axis ticks, crosshair snapping, and tooltips all follow the zoomed domain. The y-domain stays FULL (derived from all data, not the visible slice). While zoomed, a built-in "Reset zoom" button restores the full domain; `resetZoom()` / `setZoomDomain()` on the instance drive it programmatically. Off by default. |
onZoomChange | (domain: [number, number] | null) => void | - | Called when the zoom domain changes: the zoomed [min, max] in axis units (epoch ms on date axes), or null when reset to the full domain. |
singlePointLine | boolean | SinglePointLineConfig | - | true / config draws a horizontal guide line for single-point series. |
fontFamily | string | - | Font family for axis/title/tooltip text (SVG + canvas). Sets the --michi-vz-font-family CSS var so both renderers resolve it. |
filter | Filter | - | Top-N / sort filter applied to the data before rendering |
progressiveDraw | boolean | ProgressiveDrawConfig | - | Animate each line drawing itself left to right on mount (progressive reveal). `true` uses defaults; pass a config to tune duration, easing, tip labels, and autoplay. Off by default, so existing charts are unchanged. Respects prefers-reduced-motion: the chart then renders fully drawn instantly. Ignored by the webgpu renderer. |
isLoading | boolean | - | Show the loading overlay and skip the no-data check (legacy michi-vz parity). |
isNodata | boolean | ((dataSet: LineDataItem[] | null | undefined) => boolean) | - | No-data override: boolean, or a predicate on dataSet; default = empty/all-empty-series. |
noDataLabel | string | - | Text for the vanilla default no-data overlay (ignored when suppressed). |
suppressDefaultOverlay | boolean | - | A framework wrapper sets this to render its OWN loading/no-data node instead. |
tooltipFormatter | (d: DataPoint, series: DataPoint[], dataSet: LineDataItem[]) => string | - | Returns custom tooltip HTML for a hovered datum (sanitized before it is inserted) |
sharedTooltip | boolean | false | When true, hovering anywhere in the plot shows ONE tooltip listing every series' value at the nearest x (year) - the "shared"/crosshair tooltip - instead of the single nearest series. Pairs with the crosshair (enableMouseLine, on by default). |
sharedTooltipFormatter | (input: { x: number | string; xLabel: string; entries: Array<{ label: string; value: number; color: string; d: DataPoint }>; }) => string | - | Custom HTML for the shared tooltip. `entries` is one row per series that has a point at the hovered x, in dataSet order, each with its resolved colour. |
onHighlightItem | (labels: string[]) => void | - | Called when the hovered/highlighted label(s) change |
svgChildren | string | - | Pre-serialised SVG markup injected as direct <svg> children (axis-title text, reference lines). The React wrapper fills this from `children`; mirrors the legacy <LineChart>'s `{children}` slot. |
Common props - shared by every chart (14)
| Prop | Type | Default | Description |
|---|---|---|---|
width | number | 1000 | Chart width in pixels |
height | number | 500 | Chart height in pixels |
margin | Margin | { top: 50, right: 50, bottom: 50, left: 60 } | Inner margins (top/right/bottom/left, in px); default 8 (36 top with a title) |
colors | string[] | - | Categorical palette for rings without an explicit colour or colorsMapping entry |
colorsMapping | Record<string, string> | - | Explicit label -> colour map; takes precedence over the palette and per-item colours |
highlightItems | string[] | - | Labels to emphasise (active styling); others keep their base opacity |
disabledItems | string[] | - | Labels to hide entirely (ring + track removed; remaining rings keep their radii order) |
renderer | "svg" | "canvas" | "webgpu" | "svg" | Render as inline SVG (default) or to a canvas / WebGPU layer; getContext() is identical either way |
locale | string | - | BCP-47 locale used for number formatting |
skipColorMappingDispatch | boolean | false | External-CSS mode: unmapped labels resolve to transparent and onColorMappingGenerated is not emitted, so arc colours come from your CSS via the data-label-safe contract |
enableTransitions | boolean | true | Animate opacity/arc changes with CSS transitions (SVG renderer; default true) |
onColorMappingGenerated | (mapping: Record<string, string>) => void | - | Called with the resolved label -> colour map after the chart assigns colours |
onChartDataProcessed | (context: ChartContext) => void | - | Called with the renderer-agnostic ChartContext whenever the data is (re)processed |
onDataWarning | (warnings: DataWarning[]) => void | - | Called with any non-fatal data warnings (out-of-range values, duplicate labels, ...) |
Grid and axis display
Four props control the y-axis tick density and grid line rendering:
| Prop | Default | Notes |
|---|---|---|
yTicks | 10 | Approximate number of y-axis ticks. The legacy default was 10; set lower (e.g. 5) for a sparser axis. |
showGridLines | true | Horizontal dashed grid lines at each y tick. |
showVerticalGridLines | false | Vertical dashed grid lines at each x tick. The legacy chart drew none; opt in only when the extra guides help readability. |
highlightZeroLine | true | Draws the y=0 line as a solid stroke (coloured by --michi-vz-zero-line, falling back to the grid colour) rather than a regular dashed tick. Useful when a dataset spans positive and negative values. |
Loading and no-data state
The engine manages a data-mv-state attribute on the host element with three values - "loading", "nodata", and "ready" - and shows built-in overlays for the first two unless you opt out.
| Prop | Type | Default | Notes |
|---|---|---|---|
isLoading | boolean | false | Shows the .mv-loading overlay and bypasses the no-data check entirely. |
isNodata | boolean | (dataSet) => boolean | - | Overrides the default predicate (empty dataSet or every series has zero points). Pass false to force the chart to render even when data looks empty. |
noDataLabel | string | - | Text shown inside the default .mv-nodata overlay. Ignored when suppressDefaultOverlay is true. |
suppressDefaultOverlay | boolean | false | Prevents the engine from injecting its own loading/no-data node. Use this when a framework wrapper (e.g. the @michi-vz/react LineChart) renders isLoadingComponent / isNodataComponent as a React overlay instead. The host is never unmounted - the overlay is layered on top. |
React wrapper behaviour
@michi-vz/react's LineChart automatically sets suppressDefaultOverlay and renders isLoadingComponent / isNodataComponent as a positioned React node above the chart host. The chart DOM is always mounted, so isNodataComponent still fires on empty data even without a custom predicate.
Font family
fontFamily sets the CSS custom property --michi-vz-font-family on the host element, which is read by both the SVG text renderer and the canvas getComputedStyle probe. The family must already be loaded by the page - no font embedding is performed.
ChartContext / legendData
onChartDataProcessed receives a LineChartContext that extends BaseChartContext. The base now carries a legendData field:
interface LegendItem {
label: string; // series label as it appears in dataSet
color: string; // resolved colour at the time of processing
order: number; // appearance order (legend slot index)
disabled?: boolean; // true when the label is currently hidden
dataLabelSafe?: string; // sanitizeForClassName(label) - the CSS hook the canvas colour probe matches
}
interface BaseChartContext {
// ... existing fields ...
legendData?: LegendItem[]; // populated by LineChart; treat absence as []
}legendData is the canonical payload for consumer colour authorities. A framework wrapper that drives its own colour CSS (e.g. thd MonitorV2's useChartUtils) reads legendData[].{label, dataLabelSafe, color, disabled} from each onChartDataProcessed call and emits per-label stroke/fill rules targeting the data-label-safe attribute. This replaces the need to cross-reference colorsMapping with the series order.
Events
The web component dispatches these bubbling CustomEvents (the engine exposes the same via the on* callbacks in the table above):
| Event | Detail | Fires when |
|---|---|---|
michi-vz:highlight | string[] | hover highlight changes |
michi-vz:colormapping | Record<string, string> | a color mapping is generated |
michi-vz:dataprocessed | ChartContext | data is (re)processed |
michi-vz:datawarning | DataWarning[] | input warnings are detected |
getContext()
mountLineChart(el, props).getContext() returns a renderer-agnostic LineChartContext (structured stats + a deterministic natural-language summary + an a11y table). See LLM context.
Source
Props are typed as LineChartProps in @michi-vz/core.
