Tooltips allow users to see extra contextual information without overcrowding the chart.
This page covers Series tooltips. For tooltips on other chart elements, see the API options for title, subtitle, footnote, and legend items.
Default Tooltip Copy Link
The tooltip content is based on the data values and keys of the series. If provided, the _Name properties will be used instead of the _Key properties.
import React, { useState, Fragment } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
AgBarSeriesOptions,
AgCartesianChartOptions,
BarSeriesModule,
CategoryAxisModule,
LegendModule,
ModuleRegistry,
NumberAxisModule,
} from "ag-charts-community";
import { getData } from "./data";
import clone from "clone";
ModuleRegistry.registerModules([
BarSeriesModule,
CategoryAxisModule,
LegendModule,
NumberAxisModule,
]);
const ChartExample = () => {
const [options, setOptions] = useState<AgCartesianChartOptions>({
data: getData(),
series: [
{
type: "bar",
xKey: "month",
stacked: true,
yKey: "value1",
yName: "Sweaters Made",
},
{
type: "bar",
xKey: "month",
stacked: true,
yKey: "hats_made",
yName: "Hats Made",
},
],
});
const removeYNames = () => {
const nextOptions = clone(options);
for (const series of nextOptions.series ?? []) {
(series as AgBarSeriesOptions).yName = undefined;
}
setOptions(nextOptions);
};
const addYNames = () => {
const nextOptions = clone(options);
(nextOptions.series![0] as AgBarSeriesOptions).yName = "Sweaters Made";
if (nextOptions.series![1])
(nextOptions.series![1] as AgBarSeriesOptions).yName = "Hats Made";
if (nextOptions.series![2])
(nextOptions.series![2] as AgBarSeriesOptions).yName = "Gloves Made";
if (nextOptions.series![3])
(nextOptions.series![3] as AgBarSeriesOptions).yName = "Socks Made";
if (nextOptions.series![4])
(nextOptions.series![4] as AgBarSeriesOptions).yName = "Sunglasses Made";
setOptions(nextOptions);
};
const showNumSeries = (num: number) => {
const nextOptions = clone(options);
const hasYNames =
(nextOptions.series![0] as AgBarSeriesOptions).yName != null;
if (num === 1) {
nextOptions.series = [
{
type: "bar",
xKey: "month",
stacked: true,
yKey: "value1",
yName: "Sweaters Made",
},
];
} else if (num === 2) {
nextOptions.series = [
{
type: "bar",
xKey: "month",
stacked: true,
yKey: "value1",
yName: "Sweaters Made",
},
{
type: "bar",
xKey: "month",
stacked: true,
yKey: "hats_made",
yName: "Hats Made",
},
];
} else {
nextOptions.series = [
{
type: "bar",
xKey: "month",
stacked: true,
yKey: "value1",
yName: "Sweaters Made",
},
{
type: "bar",
xKey: "month",
stacked: true,
yKey: "hats_made",
yName: "Hats Made",
},
{
type: "bar",
xKey: "month",
stacked: true,
yKey: "gloves_made",
yName: "Gloves Made",
},
{
type: "bar",
xKey: "month",
stacked: true,
yKey: "socks_made",
yName: "Socks Made",
},
{
type: "bar",
xKey: "month",
stacked: true,
yKey: "sunglasses_made",
yName: "Sunglasses Made",
},
];
}
if (!hasYNames) {
for (const series of nextOptions.series ?? []) {
(series as AgBarSeriesOptions).yName = undefined;
}
}
setOptions(nextOptions);
};
return (
<Fragment>
<div className="example-controls">
<div className="controls-row">
<button onClick={removeYNames}>Remove yNames</button>
<button onClick={addYNames}>Add yNames</button>
</div>
<div className="controls-row">
<button onClick={() => showNumSeries(1)}>1 Series</button>
<button onClick={() => showNumSeries(2)}>2 Series</button>
<button onClick={() => showNumSeries(5)}>5 Series</button>
</div>
</div>
<AgCharts options={options} />
</Fragment>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);
export function getData() {
return [
{
month: "Jun",
value1: 50,
hats_made: 40,
gloves_made: 5,
socks_made: 20,
sunglasses_made: 40,
},
{
month: "Jul",
value1: 70,
hats_made: 50,
gloves_made: 5,
socks_made: 10,
sunglasses_made: 50,
},
{
month: "Aug",
value1: 60,
hats_made: 30,
gloves_made: 10,
socks_made: 20,
sunglasses_made: 30,
},
];
}
{
series: [
{ type: 'bar', xKey: 'month', stacked: true, yKey: 'value1', yName: 'Sweaters Made' },
{ type: 'bar', xKey: 'month', stacked: true, yKey: 'hats_made', yName: 'Hats Made' },
],
}In this example:
- The
yNameis used in the tooltip and legend when provided. - The default tooltip mode is:
compactwhen showing a single series with noyName.singlewhen showing more than 3 series, or a single series withyName.sharedwhen showing 3 or fewer series.
The _Name keys mirror the data keys and differ between series types. See the series specific API Reference for more details.
Tooltip Modes Copy Link
By default a shared tooltip will be used for most cartesian charts containing 3 or fewer series. Use the mode option to show a single, shared or compact tooltip.
import React, { useState, Fragment } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
AgCartesianChartOptions,
AgTooltipMode,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NumberAxisModule,
UnitTimeAxisModule,
} from "ag-charts-community";
import { getData } from "./data";
import clone from "clone";
ModuleRegistry.registerModules([
LegendModule,
LineSeriesModule,
NumberAxisModule,
UnitTimeAxisModule,
]);
const ChartExample = () => {
const [options, setOptions] = useState<AgCartesianChartOptions>({
data: getData(),
tooltip: {
mode: "single",
},
series: [
{
type: "line",
xKey: "year",
yKey: "Onshore wind",
yName: "Onshore Wind",
},
{
type: "line",
xKey: "year",
yKey: "Offshore wind",
yName: "Offshore Wind",
},
{
type: "line",
xKey: "year",
yKey: "Solar photovoltaics",
yName: "Solar Photovoltaics",
},
{
type: "line",
xKey: "year",
yKey: "Plant biomass",
yName: "Plant Biomass",
},
{
type: "line",
xKey: "year",
yKey: "Landfill gas",
yName: "Landfill Gas",
},
],
axes: {
x: {
type: "unit-time",
},
y: {
position: "right",
type: "number",
},
},
});
const setTooltipMode = (mode: AgTooltipMode) => {
const nextOptions = clone(options);
nextOptions.tooltip!.mode = mode;
setOptions(nextOptions);
};
return (
<Fragment>
<div className="example-controls">
<div className="controls-row">
<button onClick={() => setTooltipMode("single")}>Single</button>
<button onClick={() => setTooltipMode("shared")}>Shared</button>
<button onClick={() => setTooltipMode("compact")}>Compact</button>
</div>
</div>
<AgCharts options={options} />
</Fragment>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);
export function getData() {
return [
{
year: new Date(2000, 0, 1),
"Onshore wind": 81,
"Offshore wind": 0,
"Marine energy": 0,
"Solar photovoltaics": 0,
"Small scale Hydro": 18,
"Large scale Hydro": 419,
"Plant biomass": 11,
"Animal biomass": 183,
"Landfill gas": 718,
"Sewage gas": 120,
},
{
year: new Date(2001, 0, 1),
"Onshore wind": 83,
"Offshore wind": 0,
"Marine energy": 0,
"Solar photovoltaics": 0,
"Small scale Hydro": 18,
"Large scale Hydro": 331,
"Plant biomass": 81,
"Animal biomass": 205,
"Landfill gas": 822,
"Sewage gas": 119,
},
{
year: new Date(2002, 0, 1),
"Onshore wind": 108,
"Offshore wind": 0,
"Marine energy": 0,
"Solar photovoltaics": 0,
"Small scale Hydro": 18,
"Large scale Hydro": 394,
"Plant biomass": 92,
"Animal biomass": 184,
"Landfill gas": 879,
"Sewage gas": 121,
},
{
year: new Date(2003, 0, 1),
"Onshore wind": 110,
"Offshore wind": 1,
"Marine energy": 0,
"Solar photovoltaics": 0,
"Small scale Hydro": 13,
"Large scale Hydro": 257,
"Plant biomass": 137,
"Animal biomass": 169,
"Landfill gas": 1075,
"Sewage gas": 129,
},
{
year: new Date(2004, 0, 1),
"Onshore wind": 149,
"Offshore wind": 17,
"Marine energy": 0,
"Solar photovoltaics": 0,
"Small scale Hydro": 24,
"Large scale Hydro": 392,
"Plant biomass": 123,
"Animal biomass": 179,
"Landfill gas": 1313,
"Sewage gas": 144,
},
{
year: new Date(2005, 0, 1),
"Onshore wind": 215,
"Offshore wind": 35,
"Marine energy": 0,
"Solar photovoltaics": 1,
"Small scale Hydro": 38,
"Large scale Hydro": 385,
"Plant biomass": 129,
"Animal biomass": 159,
"Landfill gas": 1407,
"Sewage gas": 153,
},
{
year: new Date(2006, 0, 1),
"Onshore wind": 307,
"Offshore wind": 56,
"Marine energy": 0,
"Solar photovoltaics": 1,
"Small scale Hydro": 41,
"Large scale Hydro": 354,
"Plant biomass": 123,
"Animal biomass": 145,
"Landfill gas": 1451,
"Sewage gas": 146,
},
{
year: new Date(2007, 0, 1),
"Onshore wind": 386,
"Offshore wind": 67,
"Marine energy": 0,
"Solar photovoltaics": 1,
"Small scale Hydro": 45,
"Large scale Hydro": 392,
"Plant biomass": 138,
"Animal biomass": 218,
"Landfill gas": 1534,
"Sewage gas": 162,
},
{
year: new Date(2008, 0, 1),
"Onshore wind": 498,
"Offshore wind": 115,
"Marine energy": 0,
"Solar photovoltaics": 1,
"Small scale Hydro": 47,
"Large scale Hydro": 396,
"Plant biomass": 242,
"Animal biomass": 260,
"Landfill gas": 1540,
"Sewage gas": 180,
},
{
year: new Date(2009, 0, 1),
"Onshore wind": 647,
"Offshore wind": 151,
"Marine energy": 0,
"Solar photovoltaics": 2,
"Small scale Hydro": 49,
"Large scale Hydro": 401,
"Plant biomass": 387,
"Animal biomass": 232,
"Landfill gas": 1613,
"Sewage gas": 198,
},
{
year: new Date(2010, 0, 1),
"Onshore wind": 621,
"Offshore wind": 263,
"Marine energy": 0,
"Solar photovoltaics": 3,
"Small scale Hydro": 43,
"Large scale Hydro": 266,
"Plant biomass": 461,
"Animal biomass": 239,
"Landfill gas": 1711,
"Sewage gas": 237,
},
{
year: new Date(2011, 0, 1),
"Onshore wind": 930,
"Offshore wind": 443,
"Marine energy": 0,
"Solar photovoltaics": 21,
"Small scale Hydro": 61,
"Large scale Hydro": 429,
"Plant biomass": 554,
"Animal biomass": 224,
"Landfill gas": 1744,
"Sewage gas": 254,
},
{
year: new Date(2012, 0, 1),
"Onshore wind": 1053,
"Offshore wind": 654,
"Marine energy": 0,
"Solar photovoltaics": 116,
"Small scale Hydro": 58,
"Large scale Hydro": 398,
"Plant biomass": 1062,
"Animal biomass": 225,
"Landfill gas": 1708,
"Sewage gas": 242,
},
{
year: new Date(2013, 0, 1),
"Onshore wind": 1455,
"Offshore wind": 986,
"Marine energy": 0,
"Solar photovoltaics": 173,
"Small scale Hydro": 58,
"Large scale Hydro": 346,
"Plant biomass": 2008,
"Animal biomass": 226,
"Landfill gas": 1697,
"Sewage gas": 251,
},
{
year: new Date(2014, 0, 1),
"Onshore wind": 1595,
"Offshore wind": 1153,
"Marine energy": 0,
"Solar photovoltaics": 349,
"Small scale Hydro": 72,
"Large scale Hydro": 435,
"Plant biomass": 2913,
"Animal biomass": 225,
"Landfill gas": 1651,
"Sewage gas": 276,
},
{
year: new Date(2015, 0, 1),
"Onshore wind": 1965,
"Offshore wind": 1498,
"Marine energy": 0,
"Solar photovoltaics": 648,
"Small scale Hydro": 85,
"Large scale Hydro": 457,
"Plant biomass": 3850,
"Animal biomass": 235,
"Landfill gas": 1598,
"Sewage gas": 293,
},
{
year: new Date(2016, 0, 1),
"Onshore wind": 1785,
"Offshore wind": 1411,
"Marine energy": 0,
"Solar photovoltaics": 894,
"Small scale Hydro": 87,
"Large scale Hydro": 374,
"Plant biomass": 3855,
"Animal biomass": 230,
"Landfill gas": 1542,
"Sewage gas": 312,
},
{
year: new Date(2017, 0, 1),
"Onshore wind": 2470,
"Offshore wind": 1798,
"Marine energy": 0,
"Solar photovoltaics": 985,
"Small scale Hydro": 112,
"Large scale Hydro": 394,
"Plant biomass": 4206,
"Animal biomass": 226,
"Landfill gas": 1405,
"Sewage gas": 317,
},
{
year: new Date(2018, 0, 1),
"Onshore wind": 2612,
"Offshore wind": 2281,
"Marine energy": 1,
"Solar photovoltaics": 1089,
"Small scale Hydro": 111,
"Large scale Hydro": 357,
"Plant biomass": 4898,
"Animal biomass": 219,
"Landfill gas": 1284,
"Sewage gas": 325,
},
{
year: new Date(2019, 0, 1),
"Onshore wind": 2739,
"Offshore wind": 2749,
"Marine energy": 1,
"Solar photovoltaics": 1068,
"Small scale Hydro": 120,
"Large scale Hydro": 390,
"Plant biomass": 5400,
"Animal biomass": 243,
"Landfill gas": 866,
"Sewage gas": 233,
},
{
year: new Date(2020, 0, 1),
"Onshore wind": 3004,
"Offshore wind": 3498,
"Marine energy": 1,
"Solar photovoltaics": 1109,
"Small scale Hydro": 134,
"Large scale Hydro": 456,
"Plant biomass": 5637,
"Animal biomass": 241,
"Landfill gas": 835,
"Sewage gas": 237,
},
{
year: new Date(2021, 0, 1),
"Onshore wind": 2507,
"Offshore wind": 3053,
"Marine energy": 0,
"Solar photovoltaics": 1044,
"Small scale Hydro": 119,
"Large scale Hydro": 353,
"Plant biomass": 5990,
"Animal biomass": 240,
"Landfill gas": 791,
"Sewage gas": 233,
},
];
}
{
tooltip: {
mode: 'shared', // or 'single' or 'compact'
},
}The options for mode are:
single- shows a title, symbol and data values for a single series.shared- shows a merged tooltip, combining the tooltips of all series sharing the same x-value.compact- shows fewer data fields and uses less padding.
Tooltip Position Copy Link
By default the tooltip is anchored to the hovered datapoint. Use placement, anchorTo and offset to customise this.
import React, { useState, Fragment } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
AgCartesianChartOptions,
CategoryAxisModule,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NumberAxisModule,
} from "ag-charts-community";
import { AgTooltipAnchorTo, AgTooltipPlacement } from "ag-charts-types";
import { getData } from "./data";
import clone from "clone";
ModuleRegistry.registerModules([
CategoryAxisModule,
LegendModule,
LineSeriesModule,
NumberAxisModule,
]);
const ChartExample = () => {
const [options, setOptions] = useState<AgCartesianChartOptions>({
data: getData(),
series: [
{
type: "line",
xKey: "month",
yKey: "sweaters",
yName: "Sweaters Made",
},
],
tooltip: {
position: {
placement: "top",
offset: 12,
},
},
});
const setAnchorTo = (anchorTo: AgTooltipAnchorTo) => {
const nextOptions = clone(options);
nextOptions.tooltip!.position!.anchorTo = anchorTo;
setOptions(nextOptions);
};
const setPlacement = (placement: string) => {
const nextOptions = clone(options);
nextOptions.tooltip!.position!.placement = placement.split(
/,\s+/g,
) as AgTooltipPlacement[];
setOptions(nextOptions);
};
const setOffset = (event: Event) => {
const nextOptions = clone(options);
const value = Number((event.target as HTMLInputElement).value);
document.getElementById("offsetValue")!.textContent = String(value);
nextOptions.tooltip!.position!.offset = value;
setOptions(nextOptions);
};
return (
<Fragment>
<div className="example-controls">
<div className="controls-row">
<span>Anchor to:</span>
<select
className="gap-right"
onChange={(event) => setAnchorTo(event.target.value)}
>
<option value="node">Node</option>
<option value="pointer">Pointer</option>
<option value="chart">Chart</option>
</select>
<span>Placement:</span>
<select
className="gap-right"
onChange={(event) => setPlacement(event.target.value)}
>
<option value="top">Top</option>
<option value="top-right">Top Right</option>
<option value="right">Right</option>
<option value="bottom-right">Bottom Right</option>
<option value="bottom">Bottom</option>
<option value="bottom-left">Bottom Left</option>
<option value="left">Left</option>
<option value="top-left">Top Left</option>
<hr />
<option value="left, right">Left + Right fallback</option>
<option value="right, left">Right + Left fallback</option>
</select>
<label htmlFor="offsetSlider">Offset:</label>
<input
type="range"
id="offsetSlider"
min="0"
max="40"
defaultValue="12"
onInput={(event) => setOffset(event)}
onChange={(event) => setOffset(event)}
/>
<span
id="offsetValue"
style={{
display: "inline-block",
minWidth: "3ch",
textAlign: "right",
}}
>
12
</span>
</div>
</div>
<AgCharts options={options} />
</Fragment>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);
export function getData() {
return [
{
month: "Jun",
sweaters: 50,
},
{
month: "Jul",
sweaters: 70,
},
{
month: "Aug",
sweaters: 60,
},
];
}
{
tooltip: {
position: {
anchorTo: 'node',
placement: ['top', 'bottom', 'left', 'right'],
offset: 12,
},
},
} Placement Copy Link
The placement option positions the tooltip relative to its anchor point, such as top or top-right. See the API Reference for the full list of values.
Fallback positions can be provided in an array of placement values. The tooltip will use the first position that has sufficient space.
{
tooltip: {
position: {
anchorTo: 'node',
placement: ['left', 'right'],
},
},
}In the above example:
- Change the 'Placement' dropdown to 'Left + Right fallback'.
- Hover the leftmost datapoint and see that the tooltip goes to the right of the marker as there is no room on the left.
Anchor Point Copy Link
The options for anchorTo are:
node- the active datapoint, such as the marker or bar.pointer- the mouse pointer or single finger touch position.chart- the chart container.
Offset Copy Link
Use tooltip.position.offset to control the gap between the tooltip and its anchor point in the placement direction, or xOffset and yOffset for specific horizontal and vertical offsets.
{
tooltip: {
position: {
anchorTo: 'node',
placement: ['right', 'left'],
offset: 20,
},
},
}In the above example:
- Change the 'Placement' dropdown to 'Left + Right fallback' and change the 'Offset' value.
- Hover the leftmost datapoint and see that the offset is applied to the right of the marker, hover the rightmost datapoint and see that the offset is applied to the left.
- The directional
offsetcan be used together withxOffsetandyOffset.
Tooltip Arrow Copy Link
The default tooltip displays an arrow below it to indicate its exact point of origin. This is removed when the tooltip is constrained by the container or has an xOffset or yOffset supplied. The directional offset does not suppress the arrow.
import React, { useState, Fragment } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
AgCartesianChartOptions,
BarSeriesModule,
CategoryAxisModule,
LegendModule,
ModuleRegistry,
NumberAxisModule,
} from "ag-charts-community";
import { getData } from "./data";
import clone from "clone";
ModuleRegistry.registerModules([
BarSeriesModule,
CategoryAxisModule,
LegendModule,
NumberAxisModule,
]);
const ChartExample = () => {
const [options, setOptions] = useState<AgCartesianChartOptions>({
data: getData(),
series: [
{
type: "bar",
xKey: "month",
stacked: true,
yKey: "value1",
yName: "Sweaters Made",
},
{
type: "bar",
xKey: "month",
stacked: true,
yKey: "hats_made",
yName: "Hats Made",
},
],
tooltip: {
showArrow: true,
},
});
const toggleTooltipArrow = () => {
const nextOptions = clone(options);
nextOptions.tooltip!.showArrow = !nextOptions.tooltip!.showArrow;
setOptions(nextOptions);
};
return (
<Fragment>
<div className="example-controls">
<div className="controls-row">
<button onClick={toggleTooltipArrow}>Toggle Tooltip Arrow</button>
</div>
</div>
<AgCharts options={options} />
</Fragment>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);
export function getData() {
return [
{
month: "Jun",
value1: 50,
hats_made: 40,
},
{
month: "Jul",
value1: 70,
hats_made: 50,
},
{
month: "Aug",
value1: 60,
hats_made: 30,
},
];
}
Use the tooltip.showArrow option to change this behaviour.
{
tooltip: {
showArrow: false,
},
} Tooltip Pagination Copy Link
Pagination allows cycling through overlapping datapoints by hovering and then clicking on the mouse. Use pagination: true to enable.
import React, { useState } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
AgCartesianChartOptions,
BubbleSeriesModule,
CategoryAxisModule,
LegendModule,
ModuleRegistry,
NumberAxisModule,
} from "ag-charts-community";
import { DataType, getData } from "./data";
ModuleRegistry.registerModules([
BubbleSeriesModule,
CategoryAxisModule,
LegendModule,
NumberAxisModule,
]);
const ChartExample = () => {
const [options, setOptions] = useState<AgCartesianChartOptions<DataType>>({
data: getData(),
title: {
text: "Most Populous Cities",
},
footnote: {
text: "Source: Simple Maps",
},
series: [
{
type: "bubble",
title: "Most populous cities",
xKey: "lon",
xName: "Longitude",
yKey: "lat",
yName: "Latitude",
sizeKey: "population",
sizeName: "Population",
labelKey: "city",
labelName: "City",
maxSize: 50,
tooltip: {
renderer: ({ datum }) => ({ title: datum.city }),
},
},
],
tooltip: {
pagination: true,
},
});
return <AgCharts options={options} />;
};
const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);
// Source: https://simplemaps.com/data/world-cities
export interface DataType {
city: string;
lat: number;
lon: number;
population: number;
}
export function getData(): DataType[] {
return [
{ city: "Tokyo, Japan", lat: 35.685, lon: 139.7514, population: 35676000 },
{
city: "New York, United States",
lat: 40.6943,
lon: -73.9249,
population: 19354922,
},
{
city: "Mexico City, Mexico",
lat: 19.4424,
lon: -99.131,
population: 19028000,
},
{ city: "Mumbai, India", lat: 19.017, lon: 72.857, population: 18978000 },
{
city: "Sao Paulo, Brazil",
lat: -23.5587,
lon: -46.625,
population: 18845000,
},
{ city: "Delhi, India", lat: 28.67, lon: 77.23, population: 15926000 },
{
city: "Shanghai, China",
lat: 31.2165,
lon: 121.4365,
population: 14987000,
},
{ city: "Kolkata, India", lat: 22.495, lon: 88.3247, population: 14787000 },
{
city: "Los Angeles, United States",
lat: 34.1139,
lon: -118.4068,
population: 12815475,
},
{
city: "Dhaka, Bangladesh",
lat: 23.7231,
lon: 90.4086,
population: 12797394,
},
{
city: "Buenos Aires, Argentina",
lat: -34.6025,
lon: -58.3975,
population: 12795000,
},
{ city: "Karachi, Pakistan", lat: 24.87, lon: 66.99, population: 12130000 },
{ city: "Cairo, Egypt", lat: 30.05, lon: 31.25, population: 11893000 },
{
city: "Rio de Janeiro, Brazil",
lat: -22.925,
lon: -43.225,
population: 11748000,
},
{ city: "Osaka, Japan", lat: 34.75, lon: 135.4601, population: 11294000 },
{
city: "Beijing, China",
lat: 39.9289,
lon: 116.3883,
population: 11106000,
},
{
city: "Manila, Philippines",
lat: 14.6042,
lon: 120.9822,
population: 11100000,
},
{
city: "Moscow, Russia",
lat: 55.7522,
lon: 37.6155,
population: 10452000,
},
{ city: "Istanbul, Turkey", lat: 41.105, lon: 29.01, population: 10061000 },
{ city: "Paris, France", lat: 48.8667, lon: 2.3333, population: 9904000 },
{
city: "Seoul, South Korea",
lat: 37.5663,
lon: 126.9997,
population: 9796000,
},
{ city: "Lagos, Nigeria", lat: 6.4433, lon: 3.3915, population: 9466000 },
{
city: "Jakarta, Indonesia",
lat: -6.1744,
lon: 106.8294,
population: 9125000,
},
{
city: "Guangzhou, China",
lat: 23.145,
lon: 113.325,
population: 8829000,
},
{
city: "Chicago, United States",
lat: 41.8373,
lon: -87.6862,
population: 8675982,
},
{
city: "London, United Kingdom",
lat: 51.5,
lon: -0.1167,
population: 8567000,
},
{ city: "Lima, Peru", lat: -12.048, lon: -77.0501, population: 8012000 },
{ city: "Tehran, Iran", lat: 35.6719, lon: 51.4243, population: 7873000 },
{
city: "Kinshasa, Congo (Kinshasa)",
lat: -4.3297,
lon: 15.315,
population: 7843000,
},
{
city: "Bogota, Colombia",
lat: 4.5964,
lon: -74.0833,
population: 7772000,
},
{
city: "Shenzhen, China",
lat: 22.5524,
lon: 114.1221,
population: 7581000,
},
{ city: "Wuhan, China", lat: 30.58, lon: 114.27, population: 7243000 },
{
city: "Hong Kong, Hong Kong",
lat: 22.305,
lon: 114.185,
population: 7206000,
},
{ city: "Tianjin, China", lat: 39.13, lon: 117.2, population: 7180000 },
{ city: "Chennai, India", lat: 13.09, lon: 80.28, population: 7163000 },
{
city: "Taipei, Taiwan",
lat: 25.0358,
lon: 121.5683,
population: 6900273,
},
{ city: "Bengaluru, India", lat: 12.97, lon: 77.56, population: 6787000 },
{
city: "Bangkok, Thailand",
lat: 13.75,
lon: 100.5166,
population: 6704000,
},
{ city: "Lahore, Pakistan", lat: 31.56, lon: 74.35, population: 6577000 },
{
city: "Chongqing, China",
lat: 29.565,
lon: 106.595,
population: 6461000,
},
{
city: "Miami, United States",
lat: 25.7839,
lon: -80.2102,
population: 6381966,
},
{ city: "Hyderabad, India", lat: 17.4, lon: 78.48, population: 6376000 },
{
city: "Dallas, United States",
lat: 32.7936,
lon: -96.7662,
population: 5733259,
},
{ city: "Santiago, Chile", lat: -33.45, lon: -70.667, population: 5720000 },
{
city: "Philadelphia, United States",
lat: 40.0077,
lon: -75.1339,
population: 5637884,
},
{
city: "Belo Horizonte, Brazil",
lat: -19.915,
lon: -43.915,
population: 5575000,
},
{ city: "Madrid, Spain", lat: 40.4, lon: -3.6834, population: 5567000 },
{
city: "Houston, United States",
lat: 29.7869,
lon: -95.3905,
population: 5446468,
},
{ city: "Ahmadabad, India", lat: 23.0301, lon: 72.58, population: 5375000 },
{
city: "Ho Chi Minh City, Vietnam",
lat: 10.78,
lon: 106.695,
population: 5314000,
},
{
city: "Washington, United States",
lat: 38.9047,
lon: -77.0163,
population: 5289420,
},
{
city: "Atlanta, United States",
lat: 33.7627,
lon: -84.4225,
population: 5228750,
},
{ city: "Toronto, Canada", lat: 43.7, lon: -79.42, population: 5213000 },
{
city: "Singapore, Singapore",
lat: 1.293,
lon: 103.8558,
population: 5183700,
},
{ city: "Luanda, Angola", lat: -8.8383, lon: 13.2344, population: 5172900 },
{ city: "Baghdad, Iraq", lat: 33.3386, lon: 44.3939, population: 5054000 },
{
city: "Barcelona, Spain",
lat: 41.3833,
lon: 2.1834,
population: 4920000,
},
{ city: "Haora, India", lat: 22.5804, lon: 88.3299, population: 4841638 },
{ city: "Shenyang, China", lat: 41.805, lon: 123.45, population: 4787000 },
{
city: "Khartoum, Sudan",
lat: 15.5881,
lon: 32.5342,
population: 4754000,
},
{ city: "Pune, India", lat: 18.53, lon: 73.85, population: 4672000 },
{
city: "Boston, United States",
lat: 42.3188,
lon: -71.0846,
population: 4637537,
},
{
city: "Sydney, Australia",
lat: -33.92,
lon: 151.1852,
population: 4630000,
},
{
city: "Saint Petersburg, Russia",
lat: 59.939,
lon: 30.316,
population: 4553000,
},
{
city: "Chittagong, Bangladesh",
lat: 22.33,
lon: 91.8,
population: 4529000,
},
{
city: "Dongguan, China",
lat: 23.0489,
lon: 113.7447,
population: 4528000,
},
{
city: "Riyadh, Saudi Arabia",
lat: 24.6408,
lon: 46.7727,
population: 4465000,
},
{ city: "Hanoi, Vietnam", lat: 21.0333, lon: 105.85, population: 4378000 },
{
city: "Guadalajara, Mexico",
lat: 20.67,
lon: -103.33,
population: 4198000,
},
{
city: "Melbourne, Australia",
lat: -37.82,
lon: 144.975,
population: 4170000,
},
{ city: "Alexandria, Egypt", lat: 31.2, lon: 29.95, population: 4165000 },
{ city: "Chengdu, China", lat: 30.67, lon: 104.07, population: 4123000 },
{ city: "Rangoon, Burma", lat: 16.7834, lon: 96.1667, population: 4088000 },
{
city: "Phoenix, United States",
lat: 33.5722,
lon: -112.0891,
population: 4081849,
},
{ city: "Xi'an, China", lat: 34.275, lon: 108.895, population: 4009000 },
{
city: "Porto Alegre, Brazil",
lat: -30.05,
lon: -51.2,
population: 3917000,
},
{ city: "Surat, India", lat: 21.2, lon: 72.84, population: 3842000 },
{ city: "Hechi, China", lat: 23.0965, lon: 109.6091, population: 3830000 },
{
city: "Abidjan, CĂŽte DâIvoire",
lat: 5.32,
lon: -4.04,
population: 3802000,
},
{
city: "Brasilia, Brazil",
lat: -15.7833,
lon: -47.9161,
population: 3716996,
},
{ city: "Ankara, Turkey", lat: 39.9272, lon: 32.8644, population: 3716000 },
{
city: "Monterrey, Mexico",
lat: 25.67,
lon: -100.33,
population: 3712000,
},
{ city: "Yokohama, Japan", lat: 35.32, lon: 139.58, population: 3697894 },
{ city: "Nanjing, China", lat: 32.05, lon: 118.78, population: 3679000 },
{ city: "Montreal, Canada", lat: 45.5, lon: -73.5833, population: 3678000 },
{ city: "Guiyang, China", lat: 26.58, lon: 106.72, population: 3662000 },
{
city: "Recife, Brazil",
lat: -8.0756,
lon: -34.9156,
population: 3651000,
},
{
city: "Seattle, United States",
lat: 47.6211,
lon: -122.3244,
population: 3643765,
},
{ city: "Harbin, China", lat: 45.75, lon: 126.65, population: 3621000 },
{
city: "San Francisco, United States",
lat: 37.7562,
lon: -122.443,
population: 3603761,
},
{ city: "Fortaleza, Brazil", lat: -3.75, lon: -38.58, population: 3602319 },
{
city: "Zhangzhou, China",
lat: 24.5204,
lon: 117.67,
population: 3531147,
},
{
city: "Detroit, United States",
lat: 42.3834,
lon: -83.1024,
population: 3522206,
},
{ city: "Salvador, Brazil", lat: -12.97, lon: -38.48, population: 3484000 },
{
city: "Busan, South Korea",
lat: 35.0951,
lon: 129.01,
population: 3480000,
},
{
city: "Johannesburg, South Africa",
lat: -26.17,
lon: 28.03,
population: 3435000,
},
{
city: "Berlin, Germany",
lat: 52.5218,
lon: 13.4015,
population: 3406000,
},
{
city: "Algiers, Algeria",
lat: 36.7631,
lon: 3.0506,
population: 3354000,
},
{ city: "Rome, Italy", lat: 41.896, lon: 12.4833, population: 3339000 },
{
city: "Pyongyang, North Korea",
lat: 39.0194,
lon: 125.7547,
population: 3300000,
},
];
}
Pagination will only become available when two or more data points are under the cursor.
{
tooltip: {
pagination: true,
},
}In the above example:
- Hover overlapping bubbles.
- The cursor turns into a hand and the tooltip displays the number of data points under the cursor.
- Click in the current position to cycle through the data points, highlighting and displaying the tooltip for each in turn.
Customisation Copy Link
The exact contents and structure of a tooltip depends on the series and keys used.
Tooltips can contain any number of the following items, in order:-
- A heading - typically the x-value for a cartesian series.
- A series symbol - this graphically depicts a series and usually matches the legend item.
- A title - typically the identifying value for non-cartesian series.
- Some data rows - these contain one or more label and value pairs corresponding to information for a series.
Using CSS Styles Copy Link
import React, { useState } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
AgChartOptions,
BarSeriesModule,
CategoryAxisModule,
LegendModule,
ModuleRegistry,
NumberAxisModule,
} from "ag-charts-community";
import { getData } from "./data";
import "./styles.css";
ModuleRegistry.registerModules([
BarSeriesModule,
CategoryAxisModule,
LegendModule,
NumberAxisModule,
]);
const ChartExample = () => {
const [options, setOptions] = useState<AgChartOptions>({
data: getData(),
series: [
{
type: "bar",
xKey: "month",
yKey: "sweaters",
yName: "Sweaters Made",
},
],
});
return <AgCharts options={options} />;
};
const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);
.ag-charts-tooltip {
background-color: papayawhip;
border: 2px solid peachpuff;
color: maroon;
}
.ag-charts-tooltip-heading {
font-weight: bold;
}
export function getData() {
return [
{
month: "Jun",
sweaters: 50,
},
{
month: "Jul",
sweaters: 70,
},
{
month: "Aug",
sweaters: 60,
},
];
}
The default tooltip uses the following CSS classes for the tooltip elements:
ag-charts-tooltipfor the entire tooltip container.ag-charts-tooltip-headingandag-charts-tooltip-titlefor the tooltip headings and titles.ag-charts-tooltip-symbolfor the series symbol.ag-charts-tooltip-labelandag-charts-tooltip-valuefor the elements in the data rows.
Adding custom CSS to these will change the styling of all the tooltips in your app.
.ag-charts-tooltip {
background-color: papayawhip;
border: 2px solid peachpuff;
color: maroon;
}
.ag-charts-tooltip-heading {
font-weight: bold;
}Note that your styles don't override the default tooltip styles but complement them.
Modifying Content Copy Link
The tooltip's content can be customised within the default template by using a renderer callback function.
import React, { useState } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
AgCartesianSeriesTooltipRendererParams,
AgChartOptions,
BarSeriesModule,
CategoryAxisModule,
LegendModule,
ModuleRegistry,
NumberAxisModule,
} from "ag-charts-community";
import { DataType, getData } from "./data";
import "./styles.css";
function renderer({
datum,
yKey,
yName,
}: AgCartesianSeriesTooltipRendererParams<DataType>) {
return {
heading: "Clothing Production",
title: yName?.toUpperCase(),
data: [
{
label: datum.month,
value: Number(datum[yKey]).toFixed(1),
},
],
};
}
ModuleRegistry.registerModules([
BarSeriesModule,
CategoryAxisModule,
LegendModule,
NumberAxisModule,
]);
const ChartExample = () => {
const [options, setOptions] = useState<AgChartOptions<DataType>>({
data: getData(),
series: [
{
type: "bar",
xKey: "month",
tooltip: { renderer },
yKey: "sweaters",
yName: "Sweaters made",
stacked: true,
},
{
type: "bar",
xKey: "month",
tooltip: { renderer },
yKey: "hats",
yName: "Hats made",
stacked: true,
},
],
});
return <AgCharts options={options} />;
};
const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);
.ag-charts-tooltip {
background-color: gold;
}
export interface DataType {
month: string;
sweaters: number;
hats: number;
}
export function getData(): DataType[] {
return [
{
month: "Dec",
sweaters: 50,
hats: 40,
},
{
month: "Jan",
sweaters: 70,
hats: 50,
},
{
month: "Feb",
sweaters: 60,
hats: 30,
},
];
}
{
tooltip: {
renderer: function ({ datum, xKey, yKey, yName }) {
return {
heading: 'Clothing Production',
title: yName.toUpperCase(),
data: [
{
label: datum[xKey],
value: datum[yKey].toFixed(1),
},
],
};
},
},
}In this configuration:
- The
rendererreceives values associated with the highlighted data point. The actual type of theparamsobject passed into the tooltip renderer will depend on the series type being used. - The
rendererreturns an object with optionalheading,title,symbol, anddatafields. - The
headingandtitlemust be plain text. - The
datafield consists of an array oflabelandvaluefields, which are both plain text. - Returning an empty string for any field will cause it to be omitted from the rendered tooltip.
Modifying the Symbol Copy Link
The tooltip symbol (the coloured marker that represents the series) can be customised using the symbol property in the renderer's return object.
Whether the symbol defaults to use a marker, line, or both depends on the series type and options used. Use the enabled option for each element to override this.
import React, { useState, Fragment } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
AgCartesianChartOptions,
AllCommunityModule,
ModuleRegistry,
} from "ag-charts-community";
import { getData } from "./data";
import clone from "clone";
let symbolEnabled = true;
ModuleRegistry.registerModules(AllCommunityModule);
const ChartExample = () => {
const [options, setOptions] = useState<AgCartesianChartOptions>({
data: getData(),
title: { text: "Monthly Temperatures" },
series: [
{
type: "line",
xKey: "month",
yKey: "temperature",
yName: "Temperature",
tooltip: {
renderer: () => {
return {
symbol: {
marker: {
enabled: symbolEnabled,
shape: "star",
fill: "#cc0000",
},
line: {
enabled: symbolEnabled,
stroke: "#ff6b00",
},
},
};
},
},
},
],
});
const toggleSymbol = () => {
symbolEnabled = !symbolEnabled;
};
return (
<Fragment>
<div className="example-controls">
<div className="controls-row">
<button onClick={toggleSymbol}>Toggle Symbol</button>
</div>
</div>
<AgCharts options={options} />
</Fragment>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);
export interface DataType {
month: string;
temperature: number;
}
export function getData(): DataType[] {
return [
{ month: "Dec", temperature: 2 },
{ month: "Jan", temperature: -1 },
{ month: "Feb", temperature: 3 },
{ month: "Mar", temperature: 8 },
{ month: "Apr", temperature: 12 },
];
}
{
tooltip: {
renderer: function () {
return {
symbol: {
marker: {
enabled: true,
shape: 'star',
fill: '#cc0000',
},
line: {
enabled: true,
stroke: '#ff6b00',
},
},
};
},
},
}In this example:
- Click the button to toggle the symbol. This will take effect on the next hover.
- The
markershape has been changed to'star'instead of inheriting the circle shape from the series. - The marker and line colours have been changed from those used in the series.
Using Custom Tooltips Copy Link
To use a completely custom tooltip instead of modifying the contents of the default tooltip template, return an HTML string to the renderer including all the markup required.
import React, { useState } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
AgBarSeriesTooltipRendererParams,
AgChartOptions,
BarSeriesModule,
CategoryAxisModule,
LegendModule,
ModuleRegistry,
NumberAxisModule,
} from "ag-charts-community";
import { DataType, getData } from "./data";
import "./styles.css";
function renderer(params: AgBarSeriesTooltipRendererParams<DataType>) {
const { datum, fill, yKey } = params;
return (
'<div class="my-tooltip" style="--color:' +
fill +
'">' +
datum.month +
" ➼ " +
Number(datum[yKey]).toFixed(0) +
"</div>"
);
}
ModuleRegistry.registerModules([
BarSeriesModule,
CategoryAxisModule,
LegendModule,
NumberAxisModule,
]);
const ChartExample = () => {
const [options, setOptions] = useState<AgChartOptions<DataType>>({
data: getData(),
series: [
{
type: "bar",
xKey: "month",
tooltip: { renderer },
yKey: "sweaters",
yName: "Sweaters made",
stacked: true,
},
{
type: "bar",
xKey: "month",
tooltip: { renderer },
yKey: "hats",
yName: "Hats made",
stacked: true,
},
],
});
return <AgCharts options={options} />;
};
const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);
.my-tooltip {
padding: 12px;
font: 900 24px/28px sans-serif;
text-transform: uppercase;
letter-spacing: -1px;
color: var(--color);
text-shadow:
0 1px color-mix(in srgb, var(--color) 50%, #0008 50%),
0 2px color-mix(in srgb, var(--color) 50%, #0008 50%);
}
export interface DataType {
month: string;
sweaters: number;
hats: number;
}
export function getData(): DataType[] {
return [
{
month: "Dec",
sweaters: 50,
hats: 40,
},
{
month: "Jan",
sweaters: 70,
hats: 50,
},
{
month: "Feb",
sweaters: 60,
hats: 30,
},
];
}
{
series: [
{
type: 'bar',
tooltip: {
renderer: function (params) {
return (
'<div class="my-tooltip" style="--color:' +
params.fill +
'">' +
params.datum[params.xKey] +
' ➼ ' +
params.datum[params.yKey].toFixed(0) +
'</div>'
);
},
},
},
],
}In this configuration:
- The
rendererreceives values associated with the highlighted data point. The actual type of theparamsobject passed into the tooltip renderer will depend on the series type being used. - The
rendererreturns a single HTML string. - The text gets its colour from the
fillproperty in theparamsobject. This matches the colour of the series. - The label comes from
params.datum[params.xKey]which is the name of the month. - The value comes from the
params.datum[params.yKey], which we then stringify as an integer viatoFixed(0). - We used a custom class names on the returned
divelement, so that we can apply custom styling.
Tooltip Range Copy Link
The tooltip.range property specifies how near the cursor must be to a node for the tooltip to appear. This can be defined on each series, as well as on the chart level.
import React, { useState, Fragment } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
AgCartesianChartOptions,
CategoryAxisModule,
LegendModule,
LineSeriesModule,
ModuleRegistry,
NumberAxisModule,
} from "ag-charts-community";
import { getData } from "./data";
import clone from "clone";
ModuleRegistry.registerModules([
CategoryAxisModule,
LegendModule,
LineSeriesModule,
NumberAxisModule,
]);
const ChartExample = () => {
const [options, setOptions] = useState<AgCartesianChartOptions>({
tooltip: {
range: "nearest",
},
data: getData(),
series: [
{
type: "line",
xKey: "month",
yKey: "value1",
yName: "Sweaters Made",
},
{
type: "line",
xKey: "month",
yKey: "hats_made",
yName: "Hats Made",
},
],
});
const nearest = () => {
const nextOptions = clone(options);
nextOptions.tooltip = { range: "nearest" };
setOptions(nextOptions);
};
const exact = () => {
const nextOptions = clone(options);
nextOptions.tooltip = { range: "exact" };
setOptions(nextOptions);
};
const distance = () => {
const nextOptions = clone(options);
nextOptions.tooltip = { range: 10 };
setOptions(nextOptions);
};
return (
<Fragment>
<div className="example-controls">
<div className="controls-row">
<button onClick={nearest}>Nearest</button>
<button onClick={exact}>Exact</button>
<button onClick={distance}>Distance (10 Pixels)</button>
</div>
</div>
<AgCharts options={options} />
</Fragment>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);
export function getData() {
return [
{
month: "Jun",
value1: 50,
hats_made: 40,
},
{
month: "Jul",
value1: 70,
hats_made: 50,
},
{
month: "Aug",
value1: 60,
hats_made: 30,
},
];
}
Options for tooltip.range are:
'nearest'- Always shows the tooltip of the nearest node. This is the default for marker-based series such aslineandscatter.'exact'- Only shows the tooltip when the user hovers over a node. This is the default for shape-based series such asbarandpie.- An integer - Only shows the tooltip when the cursor is within the specified pixel distance of a node.
Interaction with Tooltips Copy Link
import React, { useState } from "react";
import { createRoot } from "react-dom/client";
import { AgCharts } from "ag-charts-react";
import {
AgBarSeriesTooltipRendererParams,
AgCartesianChartOptions,
BarSeriesModule,
CategoryAxisModule,
LegendModule,
ModuleRegistry,
NumberAxisModule,
} from "ag-charts-community";
import { DataType, getData } from "./data";
import "./styles.css";
function renderer(params: AgBarSeriesTooltipRendererParams<DataType>) {
return `<div class="tooltip">
<div class="tooltip-title">
${params.datum[params.xKey]}: ${params.datum[params.yKey]}
</div>
<div class="tooltip-body">
<a tabindex="0" href="#" onclick="console.log('Clicked within a tooltip')">Click here</a>
</div>
</div>`;
}
ModuleRegistry.registerModules([
BarSeriesModule,
CategoryAxisModule,
LegendModule,
NumberAxisModule,
]);
const ChartExample = () => {
const [options, setOptions] = useState<AgCartesianChartOptions<DataType>>({
data: getData(),
series: [
{
type: "bar",
xKey: "month",
yKey: "sweaters",
yName: "Sweaters Made",
tooltip: {
renderer,
interaction: {
enabled: true,
},
},
},
],
});
return <AgCharts options={options} />;
};
const root = createRoot(document.getElementById("root")!);
root.render(<ChartExample />);
.tooltip {
display: grid;
padding: 6px;
gap: 3px;
}
export interface DataType {
month: string;
sweaters: number;
}
export function getData(): DataType[] {
return [
{
month: "Jun",
sweaters: 50,
},
{
month: "Jul",
sweaters: 70,
},
{
month: "Aug",
sweaters: 60,
},
];
}
By default, you cannot hover over a tooltip or select its text.
Set the series[].tooltip.interaction.enabled flag to true to enable selecting the text and clicking links within the tooltip.