Skip to main content

Chart Gestures

The CartesianChart component has opt-in support for "press" gestures, including multi-press support. At this point in time, the "press" gesture support is limited to tracking the user's fingers' x-coordinate on the chart and exposing the closest (in terms of x-coordinate) point to the user's gesture.

The goal for this press support is to allow the user to press/pan across the chart and track what x-value they're pressing/panning over.

For an introductory example, see the Adding a tooltip section of the Getting Started guide.

This "press gesture" support is outlined below.

useChartPressState​

At a high level, useChartPressState takes an initial state object and returns a ChartPressState value, which is effectively a wrapper around a group of Reanimated SharedValues used to track the user's press gesture (and the corresponding x/y values and positions).

The signature for this function is:

useChartPressState<Init extends ChartPressStateInit>(init: Init): { isActive: boolean; state: ChartPressState<Init> }

type ChartPressStateInit = { x: InputFieldType; y: Record<string, number> };
export type ChartPressState<Init extends ChartPressStateInit> = {
isActive: SharedValue<boolean>;
x: { value: SharedValue<Init["x"]>; position: SharedValue<number> };
y: Record<
keyof Init["y"],
{ value: SharedValue<number>; position: SharedValue<number> }
>;
};

You'll pass the useChartPressState().state value into the chartPressState prop of the CartesianChart component, and can use that state field to track e.g. active x-value or x-position of the users touch state. You can use the useChartPressState().isActive field to dynamically show elements with the user is actively pressing the chart.

The chartPressState prop of CartesianChart​

As outlined in the Cartesian Chart page, the chartPressState prop of the CartesianChart component will accept a ChartPressState value returned from the useChartPressState hook and use that to track the users gesture state.

Press gesture configuration​

Use chartPressConfig.pan to pass configuration through to the underlying React Native Gesture Handler pan gesture. Explicit 0 values are applied, so values such as activateAfterLongPress: 0 are valid.

When a chart is inside another gesture-aware container, such as a Gesture Handler ScrollView, pass the external gesture ref through simultaneousWithExternalGesture so scrolling and chart pressing can both be recognized.

import { useRef } from "react";
import { ScrollView } from "react-native-gesture-handler";
import { CartesianChart, useChartPressState } from "victory-native";

function ScrollableChart() {
const scrollRef = useRef<ScrollView>(null);
const { state } = useChartPressState({ x: 0, y: { value: 0 } });

return (
<ScrollView ref={scrollRef}>
<CartesianChart
data={data}
xKey="x"
yKeys={["value"]}
chartPressState={state}
chartPressConfig={{
pan: {
simultaneousWithExternalGesture: scrollRef,
},
}}
>
{/* ... */}
</CartesianChart>
</ScrollView>
);
}

Multi-press support​

The CartesianChart component can track as many fingers as you want, but two will likely be the max you'd reasonably want to use. See the multi-press guide to see an example of multi-press in action.

To support multi-press gestures, you merely generate multiple ChartPressState values using the useChartPressState hook and pass those state values into the chartPressState prop as an array. For example:

import { useChartPressState, CartesianChart } from "victory-native";

const INIT_STATE = { x: 0, y: { highTmp: 0 } } as const;

function MyChart() {
// 👇 create multiple press states
const { state: firstPress, isActive: isFirstPressActive } =
useChartPressState(INIT_STATE);
const { state: secondPress, isActive: isSecondPressActive } =
useChartPressState(INIT_STATE);


return (
<CartesianChart
// ...
yKeys={["highTmp"]}
// 👇 pass them both into chartPressState to be tracked
chartPressState={[firstPress, secondPress]}
>
{() => (
// ...
)}
</CartesianChart>
)
}