# @visx/xychart In contrast to other `visx` packages which are low-level, this package seeks to abstract some of the complexity of common visualization engineering, and exposes a **high-level** x,y (cartesian coordinate) chart API. However, it is implemented using modularized `React.context` layers for theme, canvas dimensions, x/y/color scales, data, events, and tooltips which allows for more expressivity and advanced use cases. Out of the box it supports the following: - \* many common `<*Series />` types (animated or not) such as lines, bars, etc. - \* `` (animated or not) - \* `` (animated or not) - \* `` (animated or not) - \* `` - \* `theme`ing The following illustrates basic usage to create an animated line chart with a bottom `Axis`, `Grid`, and `Tooltip`: ```tsx import { AnimatedAxis, // any of these can be non-animated equivalents AnimatedGrid, AnimatedLineSeries, XYChart, Tooltip, } from '@visx/xychart'; const data1 = [ { x: '2020-01-01', y: 50 }, { x: '2020-01-02', y: 10 }, { x: '2020-01-03', y: 20 }, ]; const data2 = [ { x: '2020-01-01', y: 30 }, { x: '2020-01-02', y: 40 }, { x: '2020-01-03', y: 80 }, ]; const accessors = { xAccessor: (d) => d.x, yAccessor: (d) => d.y, }; const render = () => ( (
{tooltipData.nearestDatum.key}
{accessors.xAccessor(tooltipData.nearestDatum.datum)} {', '} {accessors.yAccessor(tooltipData.nearestDatum.datum)}
)} />
); ``` See sections below for more detailed guidance and advanced usage, or explore the comprehensive API below.
## Basic usage
Installation ``` npm install --save @visx/xychart react-spring ``` Note: `react-spring` is a required `peerDependency` for importing `Animated*` components.
Series types The following `Series` types are currently supported and we are happy to review or consider additional Series types in the future. | Component name | Description | Usage | | --------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------- | --- | | (Animated)AreaSeries | Connect data points with a ``, with a color fill to the zero baseline | `` | | (Animated)BarSeries | Render a `` for each data point | `` | | (Animated)BarGroup | Group multiple child `` values together | `...` | | (Animated)BarStack | Stack multiple child `` values together | `...` | | | (Animated)GlyphSeries | Render a `Glyph` (any shape, defaults to ``) for each data point, e.g., a scatter plot | ` ...} />` | | (Animated)LineSeries | Connect data points with a `` | `` | All `Series` have animated and non-animated variants to give you more control over your bundle size, support missing (`null`) data, and can be rendered vertically or horizontally.
Theming Default `lightTheme` and `darkTheme` themes are exported from `@visx/xychart` and the utility `buildChartTheme` is exported to support easy creation of custom themes. ```ts import { buildChartTheme, XYChart } from '@visx/xychart'; import { TextProps as SVGTextProps } from '@visx/text/lib/Text'; // just for types const customTheme = buildChartTheme({ // colors backgroundColor: string, // used by Tooltip, Annotation colors: string[], // categorical colors, mapped to series via `dataKey`s // labels svgLabelBig?: SVGTextProps, svgLabelSmall?: SVGTextProps, htmlLabel?: HTMLTextStyles, // lines xAxisLineStyles?: LineStyles, yAxisLineStyles?: LineStyles, xTickLineStyles?: LineStyles, yTickLineStyles?: LineStyles, tickLength: number, // grid gridColor: string, gridColorDark: string, // used for axis baseline if x/yxAxisLineStyles not set gridStyles?: CSSProperties, }); () => ``` For new charts built from low-level visx primitives, use `@visx/theme` as the shared visual token layer. `@visx/xychart` themes remain supported for `XYChart`, while `@visx/theme` is designed for RSC-safe CSS variable scoping, shadcn/ui-style tokens, and prop-driven primitive charts. Existing `XYChartTheme` objects can be reused with `fromXYChartTheme`: ```tsx import { buildChartTheme } from '@visx/xychart'; import { ThemeScope, fromXYChartTheme } from '@visx/theme'; const xychartTheme = buildChartTheme({ backgroundColor: '#ffffff', colors: ['#3b82f6', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6'], gridColor: '#f3f4f6', gridColorDark: '#e5e7eb', tickLength: 4, }); const primitiveTheme = fromXYChartTheme(xychartTheme); ; ```
Tooltips `@visx/tooltip` `Tooltip`s are integrated into `@visx/xychart`, and should be rendered as a child of `XYChart` (or a child where `TooltipContext` is provided). **`Tooltip` positioning** is handled by the `Tooltip` itself, based on `TooltipContext`. `Tooltip` is rendered inside a `Portal`, avoiding clipping by parent DOM elements with higher z-index contexts. See the API below for a full list of `props` to support additional behavior, such as snapping to data point positions and rendering cross-hairs. **`Tooltip` content** is controlled by the specified `prop.renderTooltip` which has access to: - `tooltipData.nearestDatum` – the globally closest `Datum`, **across all** `Series`'s `dataKey`s - `tooltipData.datumByKey` – the closest `Datum` **for each** `Series`'s `dataKey`; this enables "shared tooltips" where you can render the nearest data point for each `Series`. - a shared `colorScale` which maps `Series`'s `dataKey`s to `theme` colors
Event handlers The following `PointerEvent`s (handling both `MouseEvent`s and `TouchEvent`s) are currently supported. They may be set on individual `Series` components (e.g., ` ...} />`), or at the chart level (e.g., ` {}} />`) in which case they are invoked once for _every_ `*Series`. To **disable** event emitting for any `Series` set `<*Series enableEvents=false />`. The `onFocus/onBlur` handlers enable you to make your chart events and `Tooltip`s accessible via keyboard interaction. Note that the current implementation requires your target browser to support the `SVG 2.0` spec for `tabIndex` on `SVG` elements. Below, `HandlerParms` has the following type signature: ```ts type EventHandlerParams = { datum: Datum; // nearest Datum to event, for Series with `dataKey=key` distanceX: number; // x distance between event and Datum, in px distanceY;: number; // y distance between event and Datum, in px event: React.PointerEvent | React.FocusEvent; // the event index: number; // index of Datum in Series `data` array key: string; // `dataKey` of Series to which `Datum` belongs svgPoint: { x: number; y: number }; // event position in svg-coordinates }; ``` | Prop name | Signature | `XYChart` support | `*Series` support | | --------------- | --------------------------------------------- | ----------------- | ----------------- | | `onPointerMove` | `(params: EventHandlerParams) => void` | ✅ | ✅ | | `onPointerOut` | `(event: React.PointerEvent) => void` | ✅ | ✅ | | `onPointerUp` | `(params: EventHandlerParams) => void` | ✅ | ✅ | | `onPointerDown` | `(params: EventHandlerParams) => void` | ✅ | ✅ | | `onFocus` | `(params: EventHandlerParams) => void` | ❌ | ✅ | | `onBlur` | `(event: React.TouchEvent) => void` | ❌ | ✅ |
Annotations Composable `@visx/annotations` annotations are integrated into `@visx/xychart` and use its theme and dimension context. These components allow for annotation of individual points using `AnnotationCircleSubject`, or x- or y-thresholds using `AnnotationLineSubject`. [CodeSandbox](https://codesandbox.io/s/annotations-8npmf?file=/Example.tsx) ```tsx import React from 'react'; import { Annotation, AnnotationLabel, AnnotationConnector, AnnotationCircleSubject, Grid, LineSeries, XYChart, } from '@visx/xychart'; const data = [ { x: '2020-01-01', y: 50 }, { x: '2020-01-02', y: 10 }, { x: '2020-01-03', y: 20 }, { x: '2020-01-04', y: 5 }, ]; const labelXOffset = -40; const labelYOffset = -50; const chartConfig = { xScale: { type: 'band' }, yScale: { type: 'linear' }, height: 300, margin: { top: 10, right: 10, bottom: 10, left: 10 }, }; export default () => ( d.x} yAccessor={d => d.y} /> {/** Text label */} {/** Draw circle around point */} {/** Connect label to CircleSubject */} ); ```

##### ⚠️ `ResizeObserver` dependency Responsive `XYChart`s, `Tooltip`, and `AnnotationLabel` components rely on [`ResizeObserver`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver)s. If your browser target needs a polyfill, you can either pollute the `window` object or inject it cleanly using the `resizeObserverPolyfill` prop for these components. A polyfill passed to `XYChart` will be accessible to child `Tooltip` and `AnnotationLabel` components.
Examples ✅ ❌ ❌ `Error: This browser does not support ResizeObserver out of the box` ```tsx // no polyfill, no browser support () => () => ``` ✅ No errors ```tsx // no polyfill, target browser supports ResizeObserver () => () => // import the polyfill in the needed module, or set it on `window` object import ResizeObserver from 'resize-observer-polyfill'; () => // 😎 // cleanly pass polyfill to component that needs it import ResizeObserver from 'resize-observer-polyfill'; () => ( ) ```

## Advanced usage
Examples `XYChart` is implemented using modularized `React.context` layers for scales, canvas dimensions, data, events, and tooltips which enables more advanced usage than many other chart-level abstractions. By default `XYChart` renders all context providers if a given context is not available, but you can share context across multiple `XYChart`s to implement functionality such as linked tooltips, shared themes, or shared data. - [`ThemeProvider` + custom theme chart background example](https://codesandbox.io/s/themeprovider-sbdvz?file=/Example.tsx) - [`DataProvider/EventEmitterProvider` example of linked tooltips / small multiples](https://codesandbox.io/s/linked-tooltips-7s0jz?file=/Example.tsx) - [`TooltipProvider` example of programmatic + keyboard tooltip triggering](https://codesandbox.io/s/programmatic-tooltips-hh7ly?file=/Example.tsx)
DataContext This context provides chart canvas dimensions (`width`, `height`, and `margin`), x/y/color scales, and a data registry. The data registry includes data from all child `*Series`, and x/y/color scales are updated accordingly accounting for canvas dimensions.
ThemeContext This context provides an `XYChart` theme, its used by all visual elements that compose a chart, and can be used to render custom visual elements that are on theme.
EventEmitterContext This context provides an event publishing / subscription object which can be used via the `useEventEmitter` hook. `Series` and `XYChart` events, including tooltip updates, are emitted and handled with through this context. [CodeSandbox](https://codesandbox.io/s/eventemitterprovider-w8jhl?file=/Example.tsx) ```tsx import React, { useState } from 'react'; import { useEventEmitter, EventEmitterProvider } from '@visx/xychart'; const eventSourceId = 'optional-source-id-filter'; const EmitEvent = () => { const emit = useEventEmitter(); return ( ); }; const SubscribeToEvent = () => { const [clickCount, setClickCount] = useState(0); const allowedEventSources = [eventSourceId]; useEventEmitter('pointerup', () => setClickCount(clickCount + 1), allowedEventSources); return
Emitted {clickCount} events
; }; export default function Example() { return ( ); } ```
TooltipContext This context provides access to `@visx/tooltip`s `useTooltip` state, including whether the tooltip is visible (`tooltipOpen`), tooltlip position (`tooltipLeft`, `tooltipTop`), `tooltipData: { nearestDatum, datumByKey }` described above, and functions to update context (`hideTooltip`, `showTooltip`, and `updateTooltip`).