Chart
Draw any chart that TanStack Charts can describe, with native elements. Describe the chart with TanStack's defineChart and pass it to <ui-chart>, which draws it and handles touch, tooltips, screen readers, pan and zoom, and dark mode.
For one series, the Line, Area, Bar, Scatter and Candlestick presets are quicker. Use <ui-chart> for several series, overlays, or marks the presets don't offer.
Installation
dolan add also installs the npm packages the chart imports, @tanstack/charts and d3-shape. If that install fails, it prints the command to run yourself.
Usage
- A definition maps fields of your data to a mark's channels (
x,y,fill, …) and configures the scales. - Import
defineChartand the marks from@tanstack/charts/universal, the entry point without browser code. Scales come from@tanstack/charts/scales/*. - The TanStack Charts docs cover every mark, scale and option. Don't use
@tanstack/charts/angular: it draws into the browser DOM, which Lynx doesn't have.
Data from a signal
Build the definition in a computed() so the chart redraws when the data changes, and bind [definition]="definition()":
Size
Without width or height, the chart fills its container's width and is 200px tall. It redraws when its layout changes, for example on rotation. Set the height with a class, or fix either side in px:
Series and marks
Put every series in one array and split them with the z channel. Each series takes the next palette color, var(--chart-1) to var(--chart-5).
focus: 'group-x'focuses every series at the touched x value, so the tooltip lists them together.- If each series is its own array, give each a mark with a fixed
z:lineY(lastYear, { x: 'month', y: 'value', z: () => 'Last year' }). - For a legend, lay out
<view>swatches next to the chart. Thebg-chart-1tobg-chart-5classes match the series colors.
List several marks to layer them. They share the scales, and each draws over the ones before it:
- Rules don't take focus, so a touch still lands on the bars.
- For a trend line, use
linearRegressionY(points, { x: 'x', y: 'y', ci: 0 })before adotmark.ci: 0leaves out the confidence band. - For smooth lines and areas, pass
curve: d3Curve(curveMonotoneX), withcurveMonotoneXfromd3-shape. It never overshoots the data.
To keep a preset's axes and styling, start from its definition function and add marks. Each preset exports one, such as lineChartDefinition:
Tooltips
Put tooltip in the definition to show a tooltip for the touched point. Without it, a touch still focuses points and emits focusChange.
- Import
tooltipfrom the chart component, not from@tanstack/charts/tooltip, which is built from browser DOM elements. This one draws native views. - Pass TanStack's tooltip options with
use, as intooltip: { use: tooltip, sticky: false }. Seetooltipfor the options it reads.
To lay out the tooltip yourself, put an <ng-template uiChartTooltip> inside the chart. The chart still places the tooltip and draws its card.
Import UiChartTooltip and LYNX_ELEMENTS in your component. The template gets a UiChartTooltipContext. A point's datum is typed unknown there, so read its fields in a component method that casts it.
Touch, selection and zoom
- Scrub: touch and drag. Focus follows the nearest point, which the chart highlights and shows in the tooltip.
- Tap: emits the point from
pointSelectand pins the tooltip. While it's pinned, touches don't move focus. The next tap unpins it. Withsticky: false, a tap doesn't pin. - If a scrolling parent takes over the touch, focus clears. A pinned tooltip stays.
ChartPoint comes from @tanstack/charts/types. Its datum is the row you passed to the mark. Both outputs fire inside the touch, so wrap router navigation in setTimeout (see the setTimeout rule).
By default a touch focuses the nearest point within 48px (maxFocusDistance). Set focus in the definition to change that: 'nearest-x' prefers the closest x value, 'group-x' takes every series at that x, and false turns focus off. A TanStack selection controller in the definition is told about each tap.
Pan and zoom
Set zoomable to let users drag to pan, with +, − and 1:1 (reset) buttons in the top-right corner.
- Zoom works on continuous axes in
scales.xandscales.y, such asscaleLinear. Band and point scales don't zoom, and an axis missing fromscalesstays fixed. - On a zoomable chart, a drag pans instead of moving focus. A short tap still selects a point.
- There's no pinch to zoom, because Lynx has no native pinch handler yet.
- For your own controls, set
showZoomControlstofalseand callzoomIn(),zoomOut()orresetZoom()from aviewChild.required(UiChart). - Zooming doesn't touch your data or definition. The chart sets TanStack's
viewportoption on the zoomed scales.
Accessibility
The chart is one accessibility element. Set label on every chart to say what it shows; the default is 'Chart'.
- A screen reader announces the
label, then the focused point's series, x value and y value. - Two custom actions, Next point and Previous point, step focus through the points and show the tooltip.
Theming and dark mode
Give marks theme colors as CSS variables, such as var(--primary) or the palette var(--chart-1) to var(--chart-5). They switch with dark mode. Fixed colors such as #2563eb stay the same in both modes. Marks without a color take the palette in order, and text and gridlines follow var(--foreground).
Lynx draws the marks with its native <svg> element, which never sees your CSS, and Lynx can't read a variable's value from JavaScript. So chart-theme.ts keeps a copy of the theme colors, and the chart swaps each var(--token) for its value before drawing. Labels and the tooltip are native views, so they read the CSS variables directly.
If you change a color in default.css or dark.css, change it in chart-theme.ts too, or override it in your app config. Pass only the tokens you changed:
The chart has to follow the same source as your app's .dark class, or you get dark bars on a light card. The color scheme says which color table the marks use:
Set it for every chart with provideChartTheme({ colorScheme: 'system' }), or for one chart, preset or <ui-chart>, with its colorScheme input.
API
UiChart
A ChartPoint has datum (your row), xValue and yValue, groupLabel (the series name), x and y (its position in px) and color.
UiChartTooltip
<ng-template uiChartTooltip let-tooltip> replaces the tooltip's contents. Its context is a UiChartTooltipContext:
tooltip
The tooltip token: tooltip alone, or { use: tooltip, ...options }. <ui-chart> reads these TanStack options. Options that style the browser tooltip's DOM, such as className and portal, have no effect.
provideChartTheme
provideChartTheme(theme) returns a provider for every chart in its injector. Every field is optional, and light, dark and chart merge over their defaults.
Keep paints as var(--token) strings so one definition serves both color schemes. An unknown token falls back to the var()'s fallback, as in var(--brand, #2563eb), or to the foreground color.
Migrating from the old chart components
<ui-cartesian-chart> and its <ui-*-series> children are gone, and so is the ChartPoint type from cartesian-chart. Single-series charts keep their preset, which now fills its container's width (it was 320px). Use XYDatum and CandlestickDatum for the point types, and set a color scheme to match how your app switches .dark. Pinch to zoom is gone. Several series move to <ui-chart>, with one mark per series:
Related
- Line Chart, Area Chart, Bar Chart, Scatter Chart and Candlestick Chart: presets for one series
- Theming: the theme colors marks can use
- Dark mode: switch the app's
.darkclass <svg>: the element the marks are drawn with
