Skip to main content

Pan/Zoom

The CartesianChart and PolarChart components have opt-in support for "pan/zoom" gestures simply by using the useChartTransformState hook.

useChartTransformState

The useChartTransformState hook provides the necessary state management for pan and zoom gestures. It accepts an optional configuration object and returns an object with a state property.

Configuration

The hook accepts a configuration object with the following options:

type ChartTransformStateConfig = {
scaleX?: number; // Initial X-axis scale
scaleY?: number; // Initial Y-axis scale
};

Return Value

The hook returns an object with a state property that contains:

{
state: {
panActive: SharedValue<boolean>; // Whether a pan gesture is currently active
zoomActive: SharedValue<boolean>; // Whether a zoom gesture is currently active
origin: SharedValue<{ x: number; y: number }>; // The origin point for transformations
matrix: SharedValue<Matrix4>; // The current transformation matrix
offset: SharedValue<Matrix4>; // The offset transformation matrix
};
}

Basic Usage

To enable pan and zoom gestures on a chart, pass the transform state to the chart's transformState prop:

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

function MyChart() {
const {state: transformState} = useChartTransformState({
scaleX: 1.5, // Initial X-axis scale
scaleY: 1.0, // Initial Y-axis scale
});

return (
<CartesianChart
transformState={transformState}
// ... other props
>
{/* chart content */}
</CartesianChart>
)
}

If no configuration is provided, the chart will initialize with a scale of 1.0 for both axes.

Transform Gesture Configuration

You can customize the pan gesture behavior using the transformConfig prop:

<CartesianChart
transformState={state}
transformConfig={{
pan: {
activateAfterLongPress: 100, // Delay in ms before pan gesture activates
},
}}
>
{/* chart content */}
</CartesianChart>

When a chart is inside a vertical ScrollView, dimensions: "x" only controls how the chart moves after pan activation. Use pan activation/failure offsets to let vertical scroll gestures pass through while still allowing horizontal chart panning:

<CartesianChart
transformState={state}
transformConfig={{
pan: {
dimensions: "x",
activeOffsetX: [-20, 20],
failOffsetY: [-12, 12],
},
pinch: { enabled: false },
}}
>
{/* chart content */}
</CartesianChart>

Utility Functions

Several utility functions are available to help work with chart transformations:

getTransformComponents

Extracts the scale and translation components from a transformation matrix:

const { scaleX, scaleY, translateX, translateY } = getTransformComponents(matrix);

setScale

Updates the scale components of a transformation matrix:

// Set uniform scale
const newMatrix = setScale(matrix, 2.0); // scales both X and Y by 2.0

// Set different X and Y scales
const newMatrix = setScale(matrix, 2.0, 1.5); // scaleX = 2.0, scaleY = 1.5

setTranslate

Updates the translation components of a transformation matrix:

const newMatrix = setTranslate(matrix, 100, 50); // moves 100 units in X, 50 in Y

These utility functions are particularly useful when you need to programmatically modify chart transformations or read the current transformation state.

Reading the current transform in chart children

useCartesianTransformContext exposes the current Cartesian transform values to components rendered inside a CartesianChart. This is useful for opt-in drawing behavior that should compensate for zoom, such as keeping a stroke width visually stable while the chart content scales.

import { Line, useCartesianTransformContext } from "victory-native";

function TransformAwareLine({ points }) {
const { kx } = useCartesianTransformContext();
const strokeScale = Math.max(Math.abs(kx), 0.001);

return (
<Line
points={points}
color="blue"
strokeWidth={Math.max(1, 3 / strokeScale)}
/>
);
}

The hook returns { k, kx, ky, tx, ty }, where kx and ky are the current x/y scale factors and tx / ty are the current translation values. It must be used from chart children or renderOutside content rendered inside a CartesianChart.