AG Charts implements touch and multi-touch support, enabling interactivity across all devices.
Touch Options Copy Link
All interactivity is available via touch input.
For example:
- Tap the series area to show tooltips and crosshairs.
- Tap or double-tap to toggle a legend item, reset zoom, or press any of the UI buttons.
- Any click and double-click events are also triggered by a tap or double-tap.
- Long tap to bring up the context menu.
- Drag to zoom the axes, pan a zoomed chart, or interact with annotations.
- Use two finger pinch gestures to zoom in or out of a chart, and two finger drag to pan a zoomed chart.
Single Finger Touch Dragging Copy Link
By default, Single Finger Touch Drag events are handled like mouse drag events. To change the input handling behaviour of these events, use touch.dragAction.
Single Finger Drag
Drag with a single finger to pan or hover a chart.
import React, { useState, Fragment } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
AgCartesianChartOptions,
AgTouchOptions,
AnimationModule,
CandlestickSeriesModule,
ContextMenuModule,
CrosshairModule,
LegendModule,
ModuleRegistry,
NumberAxisModule,
OrdinalTimeAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
import clone from "clone";
ModuleRegistry.registerModules([
AnimationModule,
CandlestickSeriesModule,
CrosshairModule,
LegendModule,
NumberAxisModule,
OrdinalTimeAxisModule,
ZoomModule,
ContextMenuModule,
]);
const ChartExample = () => {
const [options, setOptions] = useState<AgCartesianChartOptions>({
data: getData(1e3),
animation: { enabled: false },
touch: { dragAction: "none" },
zoom: {
enabled: true,
enableAxisDragging: false,
},
initialState: {
zoom: {
ratioX: { start: 0.48, end: 0.52 },
ratioY: { start: 0.15, end: 0.6 },
},
},
series: [
{
type: "candlestick",
xKey: "timestamp",
lowKey: "low",
highKey: "high",
openKey: "open",
closeKey: "close",
},
],
});
const changeAction = (event: Event) => {
const nextOptions = clone(options);
const newAction = (event.target as HTMLInputElement).value as NonNullable<
AgTouchOptions["dragAction"]
>;
if (nextOptions.touch) {
nextOptions.touch.dragAction = newAction;
}
setOptions(nextOptions);
};
return (
<Fragment>
<div className="example-controls">
<div className="controls-row">
<span>Drag Action:</span>
<div className="button-group" role="group" aria-label="Drag Action">
<input
type="radio"
id="dragAction-none"
name="drag-action"
defaultValue="none"
defaultChecked
onChange={(event) => changeAction(event)}
/>
<label htmlFor="dragAction-none">
<code>'none'</code>
</label>
<input
type="radio"
id="dragAction-drag"
name="drag-action"
defaultValue="drag"
onChange={(event) => changeAction(event)}
/>
<label htmlFor="dragAction-drag">
<code>'drag'</code>
</label>
<input
type="radio"
id="dragAction-hover"
name="drag-action"
defaultValue="hover"
onChange={(event) => changeAction(event)}
/>
<label htmlFor="dragAction-hover">
<code>'hover'</code>
</label>
</div>
</div>
</div>
<AgCharts options={options} />
</Fragment>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);
const startPrice = 100;
const maxDailyPriceChange = 5;
const maxRangeDelta = 1;
function sfc32(a: number, b: number, c: number, d: number) {
return function () {
a >>>= 0;
b >>>= 0;
c >>>= 0;
d >>>= 0;
let t = (a + b) | 0;
a = b ^ (b >>> 9);
b = (c + (c << 3)) | 0;
c = (c << 21) | (c >>> 11);
d = (d + 1) | 0;
t = (t + d) | 0;
c = (c + t) | 0;
return (t >>> 0) / 4294967296;
};
}
function seedRandom(seed = 1337): () => number {
const realSeed = seed ^ 0xdeadbeef; // 32-bit seed with optional XOR value
// Pad seed with Phi, Pi and E.
// https://en.wikipedia.org/wiki/Nothing-up-my-sleeve_number
return sfc32(0x9e3779b9, 0x243f6a88, 0xb7e15162, realSeed);
}
export function getData(days: number) {
let currentPrice = startPrice;
const random = seedRandom();
return Array.from({ length: days }, (_, i) => {
// Note time is reversed
const close = currentPrice;
const open = close + (random() * 2 - 1) * maxDailyPriceChange;
currentPrice = open;
const high = Math.max(open, close) + random() * maxRangeDelta;
const low = Math.min(open, close) - random() * maxRangeDelta;
const timestamp = new Date(2024, 0, 0 /* End of 2023 */, -i);
return { timestamp, open, close, high, low };
}).reverse();
}
{
touch: {
dragAction: 'drag' | 'hover' | 'none',
},
}In this example:
dragAction: 'none'disables the chart's Single Finger input handling, scrolling the entire page.dragAction: 'drag'emulates mouse dragging, panning the viewport if possible.dragAction: 'hover'emulates mouse movements, updating the tooltip and highlighted node.
Two Finger Zoom-Pan Copy Link
By default, charts use two finger gestures to zoom and pan. To pass this gesture to the underlying page, set enableTwoFingerZoom: false.
Two Finger Zoom
Pinch with two fingers to zoom in and out.
import React, { useState, Fragment } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
AgCartesianChartOptions,
AnimationModule,
ContextMenuModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NumberAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
import clone from "clone";
ModuleRegistry.registerModules([
AnimationModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
NumberAxisModule,
ZoomModule,
ContextMenuModule,
]);
const ChartExample = () => {
const [options, setOptions] = useState<AgCartesianChartOptions>({
animation: { enabled: false },
touch: {
dragAction: "none",
},
zoom: {
enableDoubleClickToReset: false,
enableTwoFingerZoom: true,
},
initialState: {
zoom: {
ratioX: { start: 0.48, end: 0.52 },
ratioY: { start: 0.21, end: 0.82 },
},
},
tooltip: {
enabled: false,
},
axes: {
y: {
type: "number",
interval: {
minSpacing: 80,
maxSpacing: 120,
},
},
x: {
type: "number",
nice: false,
interval: {
minSpacing: 80,
maxSpacing: 120,
},
label: {
autoRotate: false,
},
},
},
data: getData(),
series: [
{
type: "line",
xKey: "year",
yKey: "spending",
},
],
});
const toggleTwoFingerZoom = (event: Event) => {
const nextOptions = clone(options);
const enabled = (event.target as HTMLInputElement).value === "true";
if (nextOptions.zoom) {
nextOptions.zoom.enableTwoFingerZoom = enabled;
}
setOptions(nextOptions);
};
return (
<Fragment>
<div className="example-controls">
<div className="controls-row">
<span>Two Finger Zoom:</span>
<div
className="button-group"
role="group"
aria-label="Two Finger Zoom"
>
<input
type="radio"
id="two-finger-zoom-enabled"
name="two-finger-zoom"
defaultValue="true"
defaultChecked
onChange={(event) => toggleTwoFingerZoom(event)}
/>
<label htmlFor="two-finger-zoom-enabled">Enabled</label>
<input
type="radio"
id="two-finger-zoom-disabled"
name="two-finger-zoom"
defaultValue="false"
onChange={(event) => toggleTwoFingerZoom(event)}
/>
<label htmlFor="two-finger-zoom-disabled">Disabled</label>
</div>
</div>
</div>
<AgCharts options={options} />
</Fragment>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);
const NUM_DATA_POINTS = 400;
export function getData() {
const data: Array<{ year: number; spending: number }> = [];
for (let i = 0; i < NUM_DATA_POINTS; i++) {
data.push({
year: new Date().getFullYear() - NUM_DATA_POINTS + i,
spending:
i === 0 ? random() * 100 : data[i - 1].spending + random() * 10 - 5,
});
}
return data;
}
let seed = 1234;
function random() {
seed = (seed * 16807) % 2147483647;
return (seed - 1) / 2147483646;
}
{
zoom: {
enableTwoFingerZoom: true | false,
},
} Long Tap Copy Link
Long Tapping the chart will open the Context Menu, if available.
Long Press
Hold to open the Context Menu on a chart.
import React, { useState, Fragment } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
AgCartesianChartOptions,
AnimationModule,
CategoryAxisModule,
ContextMenuModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NumberAxisModule,
} from "ag-charts-enterprise";
ModuleRegistry.registerModules([
AnimationModule,
CategoryAxisModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
NumberAxisModule,
ContextMenuModule,
]);
const ChartExample = () => {
const [options, setOptions] = useState<AgCartesianChartOptions>({
title: {
text: "Financial Performance Overview",
},
animation: { enabled: false },
data: [
{
year: 2018,
revenue: 120,
expenses: 80,
profit: 40,
investments: 30,
taxes: 20,
dividends: 10,
rAndD: 25,
},
{
year: 2019,
revenue: 140,
expenses: 90,
profit: 50,
investments: 40,
taxes: 25,
dividends: 12,
rAndD: 30,
},
{
year: 2020,
revenue: 160,
expenses: 100,
profit: 60,
investments: 50,
taxes: 30,
dividends: 15,
rAndD: 35,
},
{
year: 2021,
revenue: 180,
expenses: 110,
profit: 70,
investments: 55,
taxes: 35,
dividends: 18,
rAndD: 40,
},
{
year: 2022,
revenue: 200,
expenses: 120,
profit: 80,
investments: 60,
taxes: 40,
dividends: 20,
rAndD: 45,
},
],
series: [
{ type: "line", xKey: "year", yKey: "revenue", yName: "Revenue" },
{ type: "line", xKey: "year", yKey: "expenses", yName: "Expenses" },
{ type: "line", xKey: "year", yKey: "profit", yName: "Profit" },
{ type: "line", xKey: "year", yKey: "investments", yName: "Investments" },
{ type: "line", xKey: "year", yKey: "taxes", yName: "Taxes" },
{ type: "line", xKey: "year", yKey: "dividends", yName: "Dividends" },
{ type: "line", xKey: "year", yKey: "rAndD", yName: "R&D Spending" },
],
});
return (
<Fragment>
<div className="example-controls"></div>
<AgCharts options={options} />
</Fragment>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);
API Reference Copy Link
Properties available on the AgTouchOptions interface.
- dragAction
'none' | 'drag' | 'hover'default: 'drag' - Sets the input handling behaviour for single-finger touch drag events. - `'none'` - ignores these events, typically causing the default page-scrolling behaviour. - `'hover'` - makes these behave like mouse hover events, showing tooltip and crosshairs. - `'drag'` - makes these behave like mouse drag events (moving while holding left-button).
Properties available on the AgTouchOptions interface.
- dragAction
'none' | 'drag' | 'hover'default: 'drag' - Sets the input handling behaviour for single-finger touch drag events. - `'none'` - ignores these events, typically causing the default page-scrolling behaviour. - `'hover'` - makes these behave like mouse hover events, showing tooltip and crosshairs. - `'drag'` - makes these behave like mouse drag events (moving while holding left-button).