Loading...
G2 exposes a set of events for accessing the chart's lifecycle and interaction information. G2 exports a ChartEvent type to define event types.
import { Chart, ChartEvent } from '@antv/g2';const chart = new Chart({container,canvas,});chart.options({type: 'interval',data: [{ genre: 'Sports', sold: 275 },{ genre: 'Strategy', sold: 115 },{ genre: 'Action', sold: 120 },{ genre: 'Shooter', sold: 350 },{ genre: 'Other', sold: 150 },],encode: {x: 'genre',y: 'sold',color: 'genre',},axis: {x: { animate: false },y: { animate: false },},});chart.on('interval:click', (e) => {console.log(e.data.data); // Display clicked data});chart.on('element:click', (e) => {console.log(e.data.data); // Display clicked data});chart.render();
To access the chart's lifecycle information, you can use the following approach:
chart.on(ChartEvent.AFTER_RENDER, (ev) => {console.log(ev);});
G2 currently provides the following lifecycle events:
| Event Name | Description |
|---|---|
ChartEvent.BEFORE_RENDER | Before render |
ChartEvent.BEFORE_PAINT | Before paint |
ChartEvent.AFTER_PAINT | After paint |
ChartEvent.AFTER_RENDER | After render |
ChartEvent.BEFORE_CHANGE_DATA | Before data change |
ChartEvent.AFTER_CHANGE_DATA | After data change |
ChartEvent.BEFORE_CLEAR | Before canvas clear |
ChartEvent.AFTER_CLEAR | After canvas clear |
ChartEvent.BEFORE_DESTROY | Before canvas destroy |
ChartEvent.AFTER_DESTROY | After canvas destroy |
ChartEvent.BEFORE_CHANGE_SIZE | Before canvas size change |
ChartEvent.AFTER_CHANGE_SIZE | After canvas size change |
To access the chart's interaction information, you can use the following approaches:
element eventschart.on(`element:${ChartEvent.EventType}`, (ev) => {console.log(ev);});
element eventschart.on(`${markType}:${ChartEvent.EventType}`, (ev) => {console.log(ev);});// For example, listen to click events on bars in a bar chartchart.on(`interval:${ChartEvent.CLICK}`, (ev) => {console.log(ev);});
chart.on('plot:click', (event) => console.log(event));
chart.on('component:click', (event) => console.log(event));
chart.on('label:click', (event) => console.log(event));
| Event Name | Description | Callback Parameter |
|---|---|---|
ChartEvent.CLICK | Click | Event |
ChartEvent.DBLCLICK | Double click | Event |
| Event Name | Description | Callback Parameter |
|---|---|---|
ChartEvent.POINTER_TAP | Event | |
ChartEvent.POINTER_DOWN | When pointer is pressed down | Event |
ChartEvent.POINTER_UP | When pointer is released | Event |
ChartEvent.POINTER_OVER | When pointer enters the target element | Event |
ChartEvent.POINTER_OUT | When pointer leaves the target element | Event |
ChartEvent.POINTER_MOVE | When pointer changes coordinates | Event |
ChartEvent.POINTER_ENTER | When pointer enters target element or its children | Event |
ChartEvent.POINTER_LEAVE | When pointer leaves target element or its children | Event |
ChartEvent.POINTER_UPOUTSIDE | Event |
To listen to drag events, you need to set the draggable and droppable properties:
chart.options({type: 'interval',style: {draggable: true,droppable: true,},});
| Event Name | Description | Callback Parameter |
|---|---|---|
ChartEvent.DRAG_START | When dragging starts | Event |
ChartEvent.DRAG | During dragging | Event |
ChartEvent.DRAG_END | When dragging completes | Event |
ChartEvent.DRAG_ENTER | When element is dragged into the target element | Event |
ChartEvent.DRAG_LEAVE | When element is dragged out of the target element | Event |
ChartEvent.DRAG_OVER | When element is dragged over the target element | Event |
ChartEvent.DROP | When element is dropped into the target element | Event |
G2 provides standardized className for various component elements in the chart, enabling more fine-grained event listening and style control.
For interaction events on components like legends and axes, it is highly recommended to use G2's high-level interaction events rather than directly manipulating DOM elements. This provides a more stable and semantically clear event handling mechanism. Related interaction documentation: Legend Filter, Legend Highlight.
For components like legends and axes, the following approaches are recommended:
Approach 1: Using High-level Interaction Events (Recommended ⭐⭐⭐⭐⭐)
import { Chart } from '@antv/g2';const chart = new Chart({container: 'container',autoFit: true,});chart.options({type: 'interval',data: [{ genre: 'Sports', sold: 275 },{ genre: 'Strategy', sold: 115 },{ genre: 'Action', sold: 120 },{ genre: 'Shooter', sold: 350 },{ genre: 'Other', sold: 150 },],encode: {x: 'genre',y: 'sold',color: 'genre',},});chart.render();// Recommended: Use high-level interaction eventschart.on('legend:filter', (e) => {const { nativeEvent, data } = e;if (!nativeEvent) return; // Filter programmatic eventsconsole.log('✅ Legend filter event:', data);console.log(' - Channel:', data.channel);console.log(' - Current selected values:', data.values);});chart.on('legend:reset', (e) => {const { nativeEvent } = e;if (!nativeEvent) return;console.log('✅ Legend reset (select all)');});
Approach 2: Listening to Specific Child Element Events (Suitable for simple custom interactions)
For custom interaction logic, you can listen to component child element events:
import { Chart } from '@antv/g2';const chart = new Chart({container: 'container',autoFit: true,});chart.options({type: 'interval',data: [{ genre: 'Sports', sold: 275 },{ genre: 'Strategy', sold: 115 },{ genre: 'Action', sold: 120 },{ genre: 'Shooter', sold: 350 },{ genre: 'Other', sold: 150 },],encode: {x: 'genre',y: 'sold',color: 'genre',},});chart.render();// Listen to legend label and marker clicksconst handleLegendClick = (event, source) => {// Method 1: Get complete data via parent container (recommended)const item = event.target.parentNode.parentNode; // marker/label -> group -> itemif (item && item.__data__) {// Find the actual legend component (className includes 'legend-category')let legend = item.parentNode;while (legend && !legend.className.includes('legend-category')) {legend = legend.parentNode;if (!legend) return;}if (legend && legend.attributes && legend.attributes.data) {const { data } = legend.attributes;const { index } = item.__data__;const itemData = data[index];console.log(`✅ Clicked ${source}:`, itemData); // {id, label, color}console.log(` - ID: ${itemData.id}`);console.log(` - Label: ${itemData.label}`);console.log(` - Color: ${itemData.color}`);}}// Method 2: Get partial information from target.attributesif (source === 'label') {console.log(' - Text:', event.target.attributes.text);} else if (source === 'marker') {console.log(' - Color:', event.target.attributes.fill);}};chart.on('g2-legend-marker:click', (e) => handleLegendClick(e, 'marker'));chart.on('g2-legend-label:click', (e) => handleLegendClick(e, 'label'));
Approach 3: Direct Canvas DOM Manipulation (Most flexible, for fully customized scenarios)
Use only when complete customization is needed:
chart.on('afterrender', () => {const { canvas } = chart.getContext();const { document } = canvas;const items = document.getElementsByClassName('g2-legend-item');items.forEach((item) => {// Utilize event bubbling: clicks on child elements bubble to containeritem.addEventListener('click', () => {// Find the actual legend componentlet legend = item.parentNode;while (legend && !legend.className.includes('legend-category')) {legend = legend.parentNode;if (!legend) return;}if (legend && legend.attributes && legend.attributes.data) {const { data } = legend.attributes;const { index } = item.__data__;const itemData = data[index]; // {id, label, color}console.log('Legend item data:', itemData);}});});});
Using className makes it easy to filter out events from certain components to avoid interference:
import { Chart } from '@antv/g2';const chart = new Chart({container: 'container',autoFit: true,});chart.options({type: 'interval',data: [{ genre: 'Sports', sold: 275 },{ genre: 'Strategy', sold: 115 },{ genre: 'Action', sold: 120 },{ genre: 'Shooter', sold: 350 },{ genre: 'Other', sold: 150 },],encode: {x: 'genre',y: 'sold',color: 'genre',},});chart.render();// Listen to plot clicks, but exclude legend clickschart.on('plot:click', (event) => {const className = event.target?.className || '';// Check if legend was clickedconst isLegendClick = className.includes('legend');if (isLegendClick) {console.log('Legend clicked, ignoring plot:click event');return;}// Handle plot click logicconsole.log('Plot area clicked', event);});
You can get specific elements via className and dynamically modify their styles:
import { Chart } from '@antv/g2';const chart = new Chart({container: 'container',autoFit: true,});chart.options({type: 'interval',data: [{ genre: 'Sports', sold: 275 },{ genre: 'Strategy', sold: 115 },{ genre: 'Action', sold: 120 },{ genre: 'Shooter', sold: 350 },{ genre: 'Other', sold: 150 },],encode: {x: 'genre',y: 'sold',color: 'genre',},});chart.render().then(() => {const { canvas } = chart.getContext();const { document } = canvas;const legendItems = document.getElementsByClassName('g2-legend-item');// Modify the first legend item's styleif (legendItems.length > 0) {const firstItem = legendItems[0];const firstMarker = firstItem.getElementsByClassName('g2-legend-marker')[0];const firstLabel = firstItem.getElementsByClassName('g2-legend-label')[0];// Add highlight styleif (firstLabel) {firstLabel.style.fontWeight = 'bold';firstLabel.style.fill = 'orange';firstLabel.style.shadowColor = '#d3d3d3';firstLabel.style.shadowBlur = 10;firstLabel.style.shadowOffsetX = 5;firstLabel.style.shadowOffsetY = 5;}}});
Combining className with element attributes allows precise targeting of specific chart elements:
import { Chart } from '@antv/g2';const chart = new Chart({container: 'container',autoFit: true,});chart.options({type: 'interval',data: [{ genre: 'Sports', sold: 275 },{ genre: 'Strategy', sold: 115 },{ genre: 'Action', sold: 120 },{ genre: 'Shooter', sold: 350 },{ genre: 'Other', sold: 150 },],encode: {x: 'genre',y: 'sold',color: 'genre',},});chart.render().then(() => {const { canvas } = chart.getContext();const { document } = canvas;const legendItems = document.getElementsByClassName('g2-legend-item');const targetText = 'Action';let targetItem = null;// Iterate through all legend labels to find target textfor (let i = 0; i < legendItems.length; i++) {const labels = legendItems[i].getElementsByClassName('g2-legend-label');if (labels.length > 0) {const labelText = labels[0].getAttribute('text') || labels[0].textContent;if (labelText === targetText) {targetItem = legendItems[i];break;}}}if (targetItem) {console.log(`✅ Found target legend: "${targetText}"`);console.log(' className:', targetItem.className);console.log(' Can execute business logic: e.g., auto-focus, highlight, etc.');// Add background color and special styles to the target legend itemconsole.log(`🎨 Adding special styles to legend "${targetText}"...`);// Get the legend item's background elementconst background = targetItem.getElementsByClassName('g2-legend-background',)[0];const label = targetItem.getElementsByClassName('g2-legend-label')[0];const marker = targetItem.getElementsByClassName('g2-legend-marker')[0];// Modify background colorif (background) {background.style.fill = '#FFF3E0'; // Light orange backgroundbackground.style.fillOpacity = 0.8;}// Also modify label styleif (label) {label.style.fill = '#FF6B00'; // Orange textlabel.style.fontWeight = 'bold';}}});
| className | Description |
|---|---|
g2-legend-title | Legend title |
g2-legend-item | Category legend item container |
g2-legend-background | Category legend item background |
g2-legend-marker | Category legend item marker |
g2-legend-label | Category legend item label text |
g2-legend-value | Category legend item value |
g2-legend-focus-icon | Category legend item focus icon |
g2-legend-ribbon | Continuous legend color ribbon |
g2-legend-track | Continuous legend slider track |
g2-legend-selection | Continuous legend selection area |
g2-legend-handle | Continuous legend slider handle |
g2-legend-handle-marker | Continuous legend handle marker |
g2-legend-handle-label | Continuous legend label/tick value |
| className | Description |
|---|---|
g2-axis-line | Axis main line |
g2-axis-tick | Axis tick line |
g2-axis-tick-item | Individual tick |
g2-axis-label | Axis tick label |
g2-axis-label-item | Individual label |
g2-axis-title | Axis title |
g2-axis-grid | Axis grid lines |
Container elements like g2-legend-item and g2-axis are typically the outermost elements of components with transparent backgrounds and no clickable rendered area. Actual click events are triggered by their child elements and then propagate to the container through event bubbling.
Legend Component Examples:
g2-legend-marker:click - Click on marker icong2-legend-label:click - Click on label textg2-legend-item:click - Container itself has no clickable areaAxis Component Examples:
g2-axis-label:click - Click on axis labelg2-axis-title:click - Click on axis titleg2-axis-line:click - Click on axis lineg2-axis:click - Container itself has no clickable areaHow to get clicked legend item data?
Child elements (marker/label) don't directly store complete data. Use the following approaches:
item.__data__.index + legend.attributes.datatext property, marker's fill property contain partial informationitem.__data__Example: Get corresponding label when clicking marker
chart.on('g2-legend-marker:click', (e) => {const item = e.target.parentNode.parentNode;if (item && item.__data__) {// Find the actual legend componentlet legend = item.parentNode;while (legend && !legend.className.includes('legend-category')) {legend = legend.parentNode;if (!legend) return;}if (legend && legend.attributes && legend.attributes.data) {const { data } = legend.attributes;const { index } = item.__data__;const itemData = data[index];console.log('Clicked marker, corresponding label is:', itemData.label);console.log('Complete data:', itemData); // {id, label, color}}}});
See Interaction - Event Examples