Intégration et nettoyage d'ECharts dans une application React
import { init, dispose } from 'echarts';
import { useEffect, useRef } from 'react';
const ChartComponent = () => {
const chartRef = useRef<any>(null);
const intervalRef = useRef<NodeJS.Timeout | null>(null);
useEffect(() => {
const container = document.getElementById('chartContainer') as HTMLElement;
chartRef.current = init(container);
const handleResize = () => chartRef.current?.resize();
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
intervalRef.current && clearInterval(intervalRef.current);
chartRef.current?.dispose();
chartRef.current = null;
};
}, []);
Gestion des événements de clic
Deux approches sont disponibles pour capturer les interactions utilisateur sur le graphique. La première méthode intercepte les clics directement sur les éléments de données, tandis que la seconde permet de détecter les clics sur l'ensemble de la zone du graphique.
// Capture sur les éléments spécifiques
chartInstance.on('click', (event) => {
const currentItem = dataSource[event.dataIndex];
fetchData(currentItem.identifier, currentItem.category);
});
// Capture sur toute la zone graphique
chartInstance.getZr().on('click', (mouseEvent) => {
const pixelPosition = [mouseEvent.offsetX, mouseEvent.offsetY];
if (chartInstance.containPixel('grid', pixelPosition)) {
const clickedIndex = chartInstance.convertFromPixel(
{ seriesIndex: 0 },
pixelPosition
)[0];
}
});
Animation de défilement automatique des tooltips
const startCarousel = () => {
let currentPosition = 0;
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
intervalRef.current = setInterval(() => {
chartInstance.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: currentPosition,
});
currentPosition = (currentPosition + 1) % categories.length;
}, 2500);
};
if (categories.length > 0) {
startCarousel();
}
Configuration complète avec graphique à barres multiples
const configureChart = (chartInstance: any, rawData: DataItem[]) => {
const categories = rawData.map(item => item.label);
const seriesConfig = buildSeriesData(rawData);
const chartOptions = {
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
formatter: formatTooltipContent,
},
dataZoom: [
{
type: 'inside',
startValue: 0,
endValue: 100,
zoomLock: false
},
{
startValue: 0,
endValue: 100,
height: 18,
bottom: 10
}
],
xAxis: {
type: 'category',
data: categories,
boundaryGap: true,
axisLine: { lineStyle: { color: '#ccc' } },
axisLabel: {
color: '#555',
rotate: 0
}
},
yAxis: {
type: 'value',
min: 0,
max: 100,
axisLabel: {
formatter: '{value}%',
color: '#555'
},
splitLine: {
lineStyle: {
color: '#eee',
type: 'dashed'
}
}
},
series: seriesConfig
};
chartInstance.setOption(chartOptions);
// Lancer le défilement automatique
const carouselTimer = setInterval(() => {
const index = Math.floor(Date.now() / 2500) % categories.length;
chartInstance.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: index
});
}, 2500);
// Gestion des clics sur la zone
chartInstance.getZr().on('click', (evt) => {
const pos = [evt.offsetX, evt.offsetY];
if (chartInstance.containPixel('grid', pos)) {
const dataIdx = chartInstance.convertFromPixel(
{ seriesIndex: 0 },
pos
)[0];
handleAreaClick(dataIdx);
}
});
};