AG Charts allows zooming into charts, making it easier to navigate large datasets.
import {
AgCartesianChartOptions,
AgCharts,
AnimationModule,
ContextMenuModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NumberAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
ModuleRegistry.registerModules([
AnimationModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
NumberAxisModule,
ZoomModule,
ContextMenuModule,
]);
const options: AgCartesianChartOptions = {
zoom: {
enabled: true,
},
tooltip: {
enabled: false,
},
axes: {
x: {
type: "number",
nice: false,
interval: {
minSpacing: 80,
maxSpacing: 120,
},
label: {
autoRotate: false,
},
},
},
data: getData(),
series: [
{
type: "line",
xKey: "year",
yKey: "spending",
},
],
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
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;
}
To enable this feature, set zoom.enabled to true.
{
zoom: {
enabled: true,
},
}In the above example you can:
- Scroll in and out with the mouse wheel or trackpad.
- Zoom and pan using touch and multi-touch functionality.
- Use + and - keys to zoom in or out (when in focus).
- Click and drag the mouse to pan around the zoomed in chart.
- Click (or touch) and drag an axis to zoom in or out on only that axis.
- Double click (or double tap) anywhere to reset the zoom.
- Double click (or double tap) an axis to reset the zoom on only that axis.
If axis[].tick.maxSpacing is provided, the axis ticks and labels will update with the zoom.
Scrolling Copy Link
This allows zooming by using the mouse wheel or trackpad, as shown in the above example and is enabled by default. To disable, use enableScrolling: false.
Anchor Point Copy Link
By default, the chart will zoom while keeping the right side of the x-axis pinned. You can change this anchor point with the anchorPointX and anchorPointY properties, setting them each to one of:
start, the left or bottom of the chart when scrolling on the x-axis or y-axis respectively,middle(default for y-axis), the middle of the chart,end(default for x-axis), the right or top of the chart when scrolling on the x-axis or y-axis respectively,pointer, keep the mouse pointer above the same position on the chart when zooming.
In the example below, we set the anchor point for both axes to the mouse pointer.
import {
AgCartesianChartOptions,
AgCharts,
AnimationModule,
CategoryAxisModule,
ContextMenuModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NumberAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
ModuleRegistry.registerModules([
AnimationModule,
CategoryAxisModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
NumberAxisModule,
ZoomModule,
ContextMenuModule,
]);
const options: AgCartesianChartOptions = {
zoom: {
enabled: true,
axes: "xy",
anchorPointX: "pointer",
anchorPointY: "pointer",
},
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",
},
],
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
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: {
anchorPointX: 'pointer',
anchorPointY: 'pointer',
},
} Scrolling Step Copy Link
When scrolling, the chart zooms in by a single step for each movement of the scroll wheel or trackpad. By default scrollingStep is set to 0.1, or 10% of the chart each time.
In the example below, we change the step to 0.4.
import {
AgCartesianChartOptions,
AgCharts,
AnimationModule,
ContextMenuModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NumberAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
ModuleRegistry.registerModules([
AnimationModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
NumberAxisModule,
ZoomModule,
ContextMenuModule,
]);
const options: AgCartesianChartOptions = {
zoom: {
enabled: true,
scrollingStep: 0.4,
},
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",
},
],
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
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: {
scrollingStep: 0.4,
},
} Axes Copy Link
By default, scrolling zoom is only enabled for the x axis. This can be changed by setting the axes property to x, y or xy.
In the example below, we enable zoom on both the x and y axes.
import {
AgCartesianChartOptions,
AgCharts,
AnimationModule,
CategoryAxisModule,
ContextMenuModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NumberAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
ModuleRegistry.registerModules([
AnimationModule,
CategoryAxisModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
NumberAxisModule,
ZoomModule,
ContextMenuModule,
]);
const options: AgCartesianChartOptions = {
zoom: {
enabled: true,
axes: "xy",
},
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",
},
],
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
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: {
axes: 'xy',
},
} Scrolling Mode Copy Link
By default, vertical mouse wheel or trackpad scrolling zooms the chart. Set scrollingMode: 'pan' to pan instead.
import {
AgCartesianChartOptions,
AgCharts,
AnimationModule,
BarSeriesModule,
CategoryAxisModule,
ContextMenuModule,
ModuleRegistry,
NumberAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
ModuleRegistry.registerModules([
AnimationModule,
BarSeriesModule,
CategoryAxisModule,
NumberAxisModule,
ZoomModule,
ContextMenuModule,
]);
const options: AgCartesianChartOptions = {
zoom: {
enabled: true,
scrollingMode: "zoom",
},
title: {
text: "Population by Country (millions)",
},
initialState: {
zoom: {
ratioY: { start: 0.6 },
},
},
axes: {
x: {
type: "number",
label: {
formatter: (params) => `${params.value}M`,
},
},
},
data: getData(),
series: [
{
type: "bar",
direction: "horizontal",
xKey: "country",
yKey: "population",
yName: "Population (millions)",
},
],
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
function setScrollingMode(event: Event) {
options.zoom!.scrollingMode = (event.target as HTMLInputElement).value as
| "zoom"
| "pan";
chart.update(options);
}
if (typeof window !== "undefined") {
// Attach external event handlers to window so they can be called from index.html
(<any>window).setScrollingMode = setScrollingMode;
}
export function getData() {
return [
{ country: "China", population: 1425 },
{ country: "India", population: 1417 },
{ country: "United States", population: 335 },
{ country: "Indonesia", population: 277 },
{ country: "Pakistan", population: 230 },
{ country: "Nigeria", population: 224 },
{ country: "Brazil", population: 216 },
{ country: "Bangladesh", population: 173 },
{ country: "Russia", population: 144 },
{ country: "Mexico", population: 129 },
{ country: "Ethiopia", population: 127 },
{ country: "Japan", population: 124 },
{ country: "Philippines", population: 117 },
{ country: "Egypt", population: 112 },
{ country: "DR Congo", population: 102 },
{ country: "Vietnam", population: 99 },
{ country: "Iran", population: 89 },
{ country: "Turkey", population: 86 },
{ country: "Germany", population: 84 },
{ country: "Thailand", population: 72 },
{ country: "United Kingdom", population: 68 },
{ country: "Tanzania", population: 66 },
{ country: "France", population: 65 },
{ country: "South Africa", population: 60 },
{ country: "Italy", population: 59 },
];
}
{
zoom: {
scrollingMode: 'pan',
},
} Panning Copy Link
This is enabled by default and allows users to click and drag to move around a zoomed chart. To disable, use enablePanning: false.
If zoom by selecting is enabled, clicking and dragging will no longer pan by default. Instead the user will need to hold down a key to switch to panning mode.
This key defaults to alt but can be set with the panKey property to one of alt, ctrl, shift or meta (the command key on MacOS or start key on Windows).
In the example below, panning can only be done by holding down the shift key while clicking and dragging.
import {
AgCartesianChartOptions,
AgCharts,
AnimationModule,
ContextMenuModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NumberAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
ModuleRegistry.registerModules([
AnimationModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
NumberAxisModule,
ZoomModule,
ContextMenuModule,
]);
const options: AgCartesianChartOptions = {
zoom: {
enabled: true,
enableSelecting: true,
panKey: "shift",
},
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",
},
],
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
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: {
panKey: 'shift',
},
} Selecting Copy Link
This method of zooming works by clicking and dragging a box to select an area on the chart. This is disabled by default. To enable, use enableSelecting: true.
In the example below, the user can only zoom in by selection, and can only zoom out by double-click to reset.
import {
AgCartesianChartOptions,
AgCharts,
AnimationModule,
ContextMenuModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NumberAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
ModuleRegistry.registerModules([
AnimationModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
NumberAxisModule,
ZoomModule,
ContextMenuModule,
]);
const options: AgCartesianChartOptions = {
zoom: {
enableAxisDragging: false,
enablePanning: false,
enableScrolling: false,
enableSelecting: true,
},
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",
},
],
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
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: {
enableAxisDragging: false,
enablePanning: false,
enableScrolling: false,
enableSelecting: true,
},
} Two Finger Zoom-Pan Copy Link
By default, using two fingers to pinch in or out will zoom the chart. It is also possible to use two fingers to pan a zoomed chart.
To disable this behaviour, use enableTwoFingerZoom: false.
import {
AgCartesianChartOptions,
AgCharts,
AnimationModule,
ContextMenuModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NumberAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
ModuleRegistry.registerModules([
AnimationModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
NumberAxisModule,
ZoomModule,
ContextMenuModule,
]);
const options: AgCartesianChartOptions = {
zoom: {
enableTwoFingerZoom: false,
},
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",
},
],
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
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: false,
},
}In the above example:
- Two fingers gestures are not consumed by the chart. Instead they zoom or scroll the entire page.
Axis Zoom Controls Copy Link
By default, a user can click and drag on any axis to change the zoom of that axis. This ignores the axes property and is enabled by default for all axes.
import {
AgCartesianChartOptions,
AgCharts,
AnimationModule,
ContextMenuModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NumberAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
ModuleRegistry.registerModules([
AnimationModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
NumberAxisModule,
ZoomModule,
ContextMenuModule,
]);
const options: AgCartesianChartOptions = {
zoom: {
enabled: true,
enableAxisDragging: true,
enableAxisScrolling: true,
axisDraggingMode: "zoom",
},
tooltip: {
enabled: false,
},
axes: {
y: {
type: "number",
position: "left",
title: {
text: "Spending",
},
interval: {
minSpacing: 80,
maxSpacing: 120,
},
},
ySecondary: {
type: "number",
position: "right",
title: {
text: "Tonnes",
},
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",
},
{
type: "line",
xKey: "year",
yKey: "tonnes",
yKeyAxis: "ySecondary",
},
],
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
function setAxisDragging(mode: "zoom" | "pan") {
options.zoom!.axisDraggingMode = mode;
chart.update(options);
}
function enableAxisDragging(enabled: "on" | "off") {
options.zoom!.enableAxisDragging = enabled === "on";
chart.update(options);
}
function enableAxisScrolling(enabled: "on" | "off") {
options.zoom!.enableAxisScrolling = enabled === "on";
chart.update(options);
}
if (typeof window !== "undefined") {
// Attach external event handlers to window so they can be called from index.html
(<any>window).setAxisDragging = setAxisDragging;
(<any>window).enableAxisDragging = enableAxisDragging;
(<any>window).enableAxisScrolling = enableAxisScrolling;
}
const NUM_DATA_POINTS = 400;
export function getData() {
const data: Array<{ year: number; spending: number; tonnes: 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,
tonnes: 0,
});
}
// Add tonnes separately to ensure the same randomisation is used for spending as other examples
for (let i = 0; i < NUM_DATA_POINTS; i++) {
data[i] = {
...data[i],
tonnes:
i === 0 ? random() * 1000 : data[i - 1].tonnes + random() * 10 - 5,
};
}
return data;
}
let seed = 1234;
function random() {
seed = (seed * 16807) % 2147483647;
return (seed - 1) / 2147483646;
}
- When using
axisDraggingMode: 'zoom'(default), dragging either of the y-axes will zoom both of them. - Use
axisDraggingMode: 'pan'to pan while dragging an axis. - Use
enableAxisDragging: falseto disable all axis dragging. - Scrolling on an axis to zoom is enabled by default. Use
enableAxisScrolling: falseto disable it.
Double-Click to Reset Copy Link
This allows users to reset the zoom by double-clicking in an empty space in the chart area, and is enabled by default. To disable, use enableDoubleClickToReset: false.
Minimum Visible Items Copy Link
The minVisibleItems option can be used to limit how far a user can zoom in to the chart.
The example below demonstrates setting minVisibleItems to 10, preventing the user from zooming beyond showing a minimum of 10 points on the line.
import {
AgCartesianChartOptions,
AgCharts,
AnimationModule,
ContextMenuModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NumberAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
ModuleRegistry.registerModules([
AnimationModule,
ContextMenuModule,
CrosshairModule,
LegendModule,
LineSeriesModule,
NumberAxisModule,
ZoomModule,
]);
const options: AgCartesianChartOptions = {
zoom: {
minVisibleItems: 10,
},
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",
},
],
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
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: 2025 - 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: {
minVisibleItems: 10,
},
} Auto Scaling Copy Link
Auto Scaling dynamically adjusts the y-axis to fit the visible data whenever the x-axis is zoomed or panned. This is enabled by default when zooming the x-axis. To disable, use autoScaling: false.
import {
AgCartesianChartOptions,
AgCharts,
AnimationModule,
CandlestickSeriesModule,
ContextMenuModule,
CrosshairModule,
LegendModule,
ModuleRegistry,
NavigatorModule,
NumberAxisModule,
OrdinalTimeAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData } from "./data";
ModuleRegistry.registerModules([
AnimationModule,
CandlestickSeriesModule,
CrosshairModule,
LegendModule,
NavigatorModule,
NumberAxisModule,
OrdinalTimeAxisModule,
ZoomModule,
ContextMenuModule,
]);
const options: AgCartesianChartOptions = {
data: getData(1e3),
animation: { enabled: false },
zoom: {
enabled: true,
anchorPointX: "pointer",
anchorPointY: "pointer",
autoScaling: {
enabled: true,
},
},
navigator: {
enabled: true,
miniChart: {
enabled: true,
},
},
series: [
{
type: "candlestick",
xKey: "timestamp",
lowKey: "low",
highKey: "high",
openKey: "open",
closeKey: "close",
},
],
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
function setAutoScaling(event: Event) {
const autoScaling = (event.target as HTMLInputElement).value === "true";
options.zoom!.autoScaling!.enabled = autoScaling;
chart.update(options);
}
if (typeof window !== "undefined") {
// Attach external event handlers to window so they can be called from index.html
(<any>window).setAutoScaling = setAutoScaling;
}
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();
}
{
zoom: {
autoScaling: {
enabled: false,
},
},
}In the above example:
- Zoom in to the chart by scrolling and then pan left and right.
- Observe how the vertical axis domain changes to fit the displayed data range.
Auto Scaling is never applied when the user has manually adjusted the y-axis by dragging it. Auto Scaling will be reapplied when the y-axis is reset, for example by double clicking on it.
On Data Change Copy Link
When data is updated while the chart is zoomed, the zoom.onDataChange options control how the zoomed view adjusts. This helps users maintain their focus when data changes, or always see the latest data.
The default strategy is preserveDomain, use onDataChange.strategy to change to one of the below.
Preserve Domain Copy Link
strategy: 'preserveDomain' preserves the current axis domain when data changes, keeping the view at the exact domain values if possible.
This is useful for appending data without disrupting users viewing a specific time period in the middle of the data.
import {
AgCartesianChartOptions,
AgCharts,
LineSeriesModule,
ModuleRegistry,
NavigatorModule,
NumberAxisModule,
TimeAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData, getNextDataPoint } from "./data";
let data = getData();
let streamingInterval: ReturnType<typeof setInterval> | null = null;
ModuleRegistry.registerModules([
LineSeriesModule,
NavigatorModule,
NumberAxisModule,
TimeAxisModule,
ZoomModule,
]);
const options: AgCartesianChartOptions = {
data,
series: [
{
type: "line",
xKey: "date",
yKey: "price",
marker: { enabled: false },
},
],
axes: {
x: {
type: "time",
nice: false,
},
y: {
type: "number",
title: { text: "Price" },
},
},
zoom: {
enabled: true,
onDataChange: {
strategy: "preserveDomain",
},
},
navigator: {
enabled: true,
miniChart: {
enabled: true,
},
},
initialState: {
zoom: {
ratioX: { start: 0.3, end: 0.7 },
},
},
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
function startUpdates() {
if (streamingInterval) return;
streamingInterval = setInterval(() => {
const nextPoint = getNextDataPoint(data);
data.push(nextPoint);
chart.applyTransaction({ add: [nextPoint] });
}, 100);
}
function stopUpdates() {
if (streamingInterval) {
clearInterval(streamingInterval);
streamingInterval = null;
}
}
function resetData() {
stopUpdates();
data = getData();
options.data = data;
chart.update(options);
}
if (typeof window !== "undefined") {
// Attach external event handlers to window so they can be called from index.html
(<any>window).startUpdates = startUpdates;
(<any>window).stopUpdates = stopUpdates;
(<any>window).resetData = resetData;
}
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;
return sfc32(0x9e3779b9, 0x243f6a88, 0xb7e15162, realSeed);
}
const random = seedRandom(12345);
export interface DataPoint {
date: Date;
price: number;
}
export function getData(): DataPoint[] {
const startDate = new Date("2024-01-01");
const data: DataPoint[] = [];
for (let i = 0; i < 50; i++) {
const date = new Date(startDate);
date.setDate(startDate.getDate() + i);
data.push({
date,
price: 100 + Math.sin(i / 5) * 20 + random() * 10,
});
}
return data;
}
export function getNextDataPoint(currentData: DataPoint[]): DataPoint {
const lastPoint = currentData[currentData.length - 1];
const nextDate = new Date(lastPoint.date);
nextDate.setDate(nextDate.getDate() + 1);
return {
date: nextDate,
price: lastPoint.price + (random() - 0.5) * 10,
};
}
{
zoom: {
enabled: true,
onDataChange: {
strategy: 'preserveDomain',
},
},
}In this example:
- The chart is initially zoomed to the middle of the data.
- Start the updates to see new data appended at the end.
- Notice in the Navigator that new data has been added, but the chart view remains fixed on the same time range.
Preserve Ratios Copy Link
strategy: 'preserveRatios', preserves the same zoom percentages regardless of data changes.
This is useful for maintaining a consistent proportional view of your data, with more data points becoming visible as the dataset grows.
import {
AgCartesianChartOptions,
AgCharts,
LineSeriesModule,
ModuleRegistry,
NavigatorModule,
NumberAxisModule,
TimeAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData, getNextDataPoint } from "./data";
let data = getData();
let streamingInterval: ReturnType<typeof setInterval> | null = null;
ModuleRegistry.registerModules([
LineSeriesModule,
NavigatorModule,
NumberAxisModule,
TimeAxisModule,
ZoomModule,
]);
const options: AgCartesianChartOptions = {
data,
series: [
{
type: "line",
xKey: "date",
yKey: "price",
marker: { enabled: false },
},
],
axes: {
x: {
type: "time",
nice: false,
},
y: {
type: "number",
title: { text: "Price" },
},
},
zoom: {
enabled: true,
onDataChange: {
strategy: "preserveRatios",
},
},
navigator: {
enabled: true,
miniChart: {
enabled: true,
},
},
initialState: {
zoom: {
ratioX: { start: 0.8, end: 1 },
},
},
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
function startUpdates() {
if (streamingInterval) return;
streamingInterval = setInterval(() => {
const newPoints = [];
for (let i = 0; i < 10; i++) {
const nextPoint = getNextDataPoint(data);
data.push(nextPoint);
newPoints.push(nextPoint);
}
chart.applyTransaction({ add: newPoints });
}, 200);
}
function stopUpdates() {
if (streamingInterval) {
clearInterval(streamingInterval);
streamingInterval = null;
}
}
function resetData() {
stopUpdates();
data = getData();
options.data = data;
chart.update(options);
}
if (typeof window !== "undefined") {
// Attach external event handlers to window so they can be called from index.html
(<any>window).startUpdates = startUpdates;
(<any>window).stopUpdates = stopUpdates;
(<any>window).resetData = resetData;
}
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;
return sfc32(0x9e3779b9, 0x243f6a88, 0xb7e15162, realSeed);
}
const random = seedRandom(12345);
export interface DataPoint {
date: Date;
price: number;
}
export function getData(): DataPoint[] {
const startDate = new Date("2024-01-01");
const data: DataPoint[] = [];
for (let i = 0; i < 50; i++) {
const date = new Date(startDate);
date.setDate(startDate.getDate() + i);
data.push({
date,
price: 100 + Math.sin(i / 5) * 20 + random() * 10,
});
}
return data;
}
let lastPrice = 0;
export function getNextDataPoint(currentData: DataPoint[]): DataPoint {
const lastPoint = currentData[currentData.length - 1];
const nextDate = new Date(lastPoint.date);
nextDate.setDate(nextDate.getDate() + 1);
lastPrice = lastPoint.price + (random() - 0.5) * 10;
return {
date: nextDate,
price: lastPrice,
};
}
{
zoom: {
enabled: true,
onDataChange: {
strategy: 'preserveRatios',
},
},
}In this example:
- The chart is initially zoomed to the last 20% of the data.
- Start the updates to see new data points added in batches.
- Notice that more data points become visible in the chart view as total data grows, since the zoom ratio stays at 80%-100%.
Reset Copy Link
strategy: 'reset', resets the zoom to the initialState or no zoom, whenever the data changes.
This is useful for switching between unrelated datasets, discarding previous user interactions and reverting to a predefined starting view.
import {
AgCartesianChartOptions,
AgCharts,
LineSeriesModule,
ModuleRegistry,
NavigatorModule,
NumberAxisModule,
TimeAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getDatasetA, getDatasetB } from "./data";
ModuleRegistry.registerModules([
LineSeriesModule,
NavigatorModule,
NumberAxisModule,
TimeAxisModule,
ZoomModule,
]);
const options: AgCartesianChartOptions = {
data: getDatasetA(),
series: [
{
type: "line",
xKey: "date",
yKey: "price",
marker: { enabled: false },
},
],
axes: {
x: {
type: "time",
nice: false,
},
y: {
type: "number",
title: { text: "Price" },
},
},
zoom: {
enabled: true,
onDataChange: {
strategy: "reset",
},
},
navigator: {
enabled: true,
miniChart: {
enabled: true,
},
},
initialState: {
zoom: {
ratioX: { start: 0.9, end: 1 },
},
},
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
function loadDatasetA() {
options.data = getDatasetA();
chart.update(options);
}
function loadDatasetB() {
options.data = getDatasetB();
chart.update(options);
}
if (typeof window !== "undefined") {
// Attach external event handlers to window so they can be called from index.html
(<any>window).loadDatasetA = loadDatasetA;
(<any>window).loadDatasetB = loadDatasetB;
}
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;
return sfc32(0x9e3779b9, 0x243f6a88, 0xb7e15162, realSeed);
}
export interface DataPoint {
date: Date;
price: number;
}
export function getDatasetA(): DataPoint[] {
const random = seedRandom(11111);
const startDate = new Date("2024-01-01");
const data: DataPoint[] = [];
for (let i = 0; i < 60; i++) {
const date = new Date(startDate);
date.setDate(startDate.getDate() + i);
data.push({
date,
price: 100 + Math.sin(i / 5) * 20 + random() * 10,
});
}
return data;
}
export function getDatasetB(): DataPoint[] {
const random = seedRandom(22222);
const startDate = new Date("2024-03-01");
const data: DataPoint[] = [];
for (let i = 0; i < 45; i++) {
const date = new Date(startDate);
date.setDate(startDate.getDate() + i);
data.push({
date,
price: 150 + Math.cos(i / 4) * 30 + random() * 15,
});
}
return data;
}
{
zoom: {
enabled: true,
onDataChange: {
strategy: 'reset',
},
},
}In this example:
- The chart is initially zoomed to show only the last few data points.
- Pan or zoom to a different position in the chart.
- Click a button to switch datasets and notice that the zoom resets to the initial state.
Stick to End Copy Link
The stickToEnd option automatically scrolls to keep the latest data visible when new data is appended and the view is already at the end of the data range. Use stickToEnd: true to enable.
When stickToEnd is active, it takes precedence over the configured strategy. Once the user pans away from the end, the configured strategy (e.g., preserveDomain) takes over until they return to viewing the end.
import {
AgCartesianChartOptions,
AgCharts,
LineSeriesModule,
ModuleRegistry,
NavigatorModule,
NumberAxisModule,
TimeAxisModule,
ZoomModule,
} from "ag-charts-enterprise";
import { getData, getNextDataPoint } from "./data";
let data = getData();
let streamingInterval: ReturnType<typeof setInterval> | null = null;
ModuleRegistry.registerModules([
LineSeriesModule,
NavigatorModule,
NumberAxisModule,
TimeAxisModule,
ZoomModule,
]);
const options: AgCartesianChartOptions = {
data,
series: [
{
type: "line",
xKey: "date",
yKey: "price",
marker: { enabled: false },
},
],
axes: {
x: {
type: "time",
nice: false,
},
y: {
type: "number",
title: { text: "Price" },
},
},
zoom: {
enabled: true,
onDataChange: {
strategy: "preserveDomain",
stickToEnd: true,
},
},
navigator: {
enabled: true,
miniChart: {
enabled: true,
},
},
initialState: {
zoom: {
ratioX: { start: 0.6, end: 1 },
},
},
};
options.container = document.getElementById("myChart");
const chart = AgCharts.create(options);
function startUpdates() {
if (streamingInterval) return;
streamingInterval = setInterval(() => {
const nextPoint = getNextDataPoint(data);
data.push(nextPoint);
chart.applyTransaction({ add: [nextPoint] });
}, 100);
}
function stopUpdates() {
if (streamingInterval) {
clearInterval(streamingInterval);
streamingInterval = null;
}
}
function resetData() {
stopUpdates();
data = getData();
options.data = data;
chart.update(options);
}
if (typeof window !== "undefined") {
// Attach external event handlers to window so they can be called from index.html
(<any>window).startUpdates = startUpdates;
(<any>window).stopUpdates = stopUpdates;
(<any>window).resetData = resetData;
}
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;
return sfc32(0x9e3779b9, 0x243f6a88, 0xb7e15162, realSeed);
}
const random = seedRandom(12345);
export interface DataPoint {
date: Date;
price: number;
}
export function getData(): DataPoint[] {
const startDate = new Date("2024-01-01");
const data: DataPoint[] = [];
for (let i = 0; i < 50; i++) {
const date = new Date(startDate);
date.setDate(startDate.getDate() + i);
data.push({
date,
price: 100 + Math.sin(i / 5) * 20 + random() * 10,
});
}
return data;
}
export function getNextDataPoint(currentData: DataPoint[]): DataPoint {
const lastPoint = currentData[currentData.length - 1];
const nextDate = new Date(lastPoint.date);
nextDate.setDate(nextDate.getDate() + 1);
return {
date: nextDate,
price: lastPoint.price + (random() - 0.5) * 10,
};
}
{
zoom: {
enabled: true,
onDataChange: {
strategy: 'preserveDomain',
stickToEnd: true,
},
},
}In this example:
- The chart is initially zoomed to the end of the data.
- Start the updates to see new data appended and the view scrolls to follow.
- Pan away from the end to see the
preserveDomainstrategy take over with a fixed view. - Pan back to the end and the view will resume following new data.
Navigator Copy Link
The zoom functionality can be used together with the Navigator to add a visual reference to the zoom position.
Context Menu Copy Link
When both the zoom and Context Menu are enabled, additional zoom actions are added into the Context Menu for zooming and panning to the clicked location.
Buttons Copy Link
Zoom buttons are enabled by default. To disable, use zoom.buttons.enabled: false.
Hover near the bottom of the above example to see the default zoom buttons.
- Zoom out: Zooms the chart out by one step.
- Zoom in: Zooms the chart in by one step.
- Pan left: Pans the chart to the left by one step.
- Pan right: Pans the chart to the right by one step.
- Reset: Resets the zoom to the original level and position. Equivalent to Double-Click to Reset.
To change when the buttons will appear, use zoom.buttons.visible:
always– The buttons will always be visible.zoomed– The buttons will appear when the chart has been zoomed.hover– The buttons will appear when the mouse is hovered near the bottom of a chart which has zoom enabled.
Customisation Copy Link
It is possible to customise the visibility, order and grouping of buttons, as well as modifying the icon, label text and tooltip for each.
{
zoom: {
buttons: {
visible: 'always',
buttons: [
{
icon: 'zoom-in',
tooltip: 'Decrease Visible Range',
value: 'zoom-in',
label: 'In',
section: 'zoom',
},
{
icon: 'zoom-out',
tooltip: 'Increase Visible Range',
value: 'zoom-out',
label: 'Out',
section: 'zoom',
},
{
icon: 'pan-start',
tooltip: 'Pan to Start',
value: 'pan-start',
section: 'pan',
},
{
icon: 'pan-end',
tooltip: 'Pan to End',
value: 'pan-end',
section: 'pan',
},
{
tooltip: 'Undo all Zoom',
value: 'reset',
label: 'Reset',
section: 'reset',
},
],
},
},
}In the above example:
- The pan-left and pan-right buttons are not shown.
- Additional buttons are added to enable panning to the start and end of the x-axis.
- All the buttons have custom tooltip text.
- The order of the zoom-in and zoom-out buttons is swapped and they have a label as well as an icon.
- The reset button has only a label and no icon.
For more information see the API Reference section.
Asynchronous Loading Copy Link
For loading data asynchronously as the user zooms and pans, see Asynchronous Data.
Save & Restore Copy Link
The zoom state can be saved, restored and programmatically initialised and modified, using the Chart State API.
API Reference Copy Link
Properties available on the AgZoomOptions interface.
- anchorPointX
AgZoomAnchorPointdefault: end - The anchor point for the x-axis about which to zoom into when scrolling.
- anchorPointY
AgZoomAnchorPointdefault: middle - The anchor point for the y-axis about which to zoom into when scrolling.
- autoScaling
AgZoomAutoScaling - Zoom auto scaling options.
- axes
AgZoomAxesdefault: x - The axes on which to zoom when scrolling, one of `xy`, `x`, or `y`.
- axisDraggingMode
AgZoomAxisDraggingModedefault: zoom - Whether dragging an axis pans or zooms, if `enableAxisDragging` is enabled.
- buttons
AgZoomButtons - A set of buttons to perform common zoom actions.
- deceleration
AgZoomDecelerationdefault: short - Rate of deceleration of panning when dragging and releasing a zoomed chart.
- enabled
booleandefault: false - Set to `true` to enable the zoom module.
- enableAxisDragging
booleandefault: true - Set to `true` to enable dragging an axis to zoom series attached to that axis.
- enableAxisScrolling
booleandefault: true - Set to `true` to enable scrolling an axis to zoom series attached to that axis.
- enableDoubleClickToReset
booleandefault: true - Set to `true` to enable double-clicking to reset the chart to fully zoomed out.
- enablePanning
booleandefault: true - Set to `true` to enable panning while zoomed.
- enableScrolling
booleandefault: true - Set to `true` to enable zooming with the mouse wheel.
- enableSelecting
booleandefault: false - Set to `true` to enable selecting an area of the chart to zoom into.
- enableTwoFingerZoom
booleandefault: true - Set to `true` to enable zoom-panning with two touch points.
- keepAspectRatio
booleandefault: false - Set to `true` to keep the selection area matching the chart's aspect ratio.
- minVisibleItems
numberdefault: 2 - The minimum number of items to be shown, beyond which zooming is stopped. Set to `0` to allow unlimited zooming.
- panKey
AgZoomPanKeydefault: alt - The key that should be pressed to allow dragging to pan around while zoomed, one of `alt`, `ctrl`, `meta` or `shift`.
- scrollingMode
AgZoomScrollingModedefault: zoom - Whether scrolling the mouse wheel or track pad vertically zooms or pans.
- scrollingStep
Ratiodefault: 0.1 - The amount to zoom when scrolling with the mouse wheel, as a ratio of the full chart.
- onDataChange
AgZoomOnDataChange - Configuration for how the zoom-pan should respond to data changes
Properties available on the AgZoomOptions interface.
- anchorPointX
AgZoomAnchorPointdefault: end - The anchor point for the x-axis about which to zoom into when scrolling.
- anchorPointY
AgZoomAnchorPointdefault: middle - The anchor point for the y-axis about which to zoom into when scrolling.
- autoScaling
AgZoomAutoScaling - Zoom auto scaling options.
- axes
AgZoomAxesdefault: x - The axes on which to zoom when scrolling, one of `xy`, `x`, or `y`.
- axisDraggingMode
AgZoomAxisDraggingModedefault: zoom - Whether dragging an axis pans or zooms, if `enableAxisDragging` is enabled.
- buttons
AgZoomButtons - A set of buttons to perform common zoom actions.
- deceleration
AgZoomDecelerationdefault: short - Rate of deceleration of panning when dragging and releasing a zoomed chart.
- enabled
booleandefault: false - Set to `true` to enable the zoom module.
- enableAxisDragging
booleandefault: true - Set to `true` to enable dragging an axis to zoom series attached to that axis.
- enableAxisScrolling
booleandefault: true - Set to `true` to enable scrolling an axis to zoom series attached to that axis.
- enableDoubleClickToReset
booleandefault: true - Set to `true` to enable double-clicking to reset the chart to fully zoomed out.
- enablePanning
booleandefault: true - Set to `true` to enable panning while zoomed.
- enableScrolling
booleandefault: true - Set to `true` to enable zooming with the mouse wheel.
- enableSelecting
booleandefault: false - Set to `true` to enable selecting an area of the chart to zoom into.
- enableTwoFingerZoom
booleandefault: true - Set to `true` to enable zoom-panning with two touch points.
- keepAspectRatio
booleandefault: false - Set to `true` to keep the selection area matching the chart's aspect ratio.
- minVisibleItems
numberdefault: 2 - The minimum number of items to be shown, beyond which zooming is stopped. Set to `0` to allow unlimited zooming.
- panKey
AgZoomPanKeydefault: alt - The key that should be pressed to allow dragging to pan around while zoomed, one of `alt`, `ctrl`, `meta` or `shift`.
- scrollingMode
AgZoomScrollingModedefault: zoom - Whether scrolling the mouse wheel or track pad vertically zooms or pans.
- scrollingStep
Ratiodefault: 0.1 - The amount to zoom when scrolling with the mouse wheel, as a ratio of the full chart.
- onDataChange
AgZoomOnDataChange - Configuration for how the zoom-pan should respond to data changes
Properties available on the AgDataSourceOptions interface.
- getData required
Function - Asynchronous callback to load data into the chart.
Properties available on the AgDataSourceOptions interface.
- getData required
Function - Asynchronous callback to load data into the chart.