I have implemented a react-echarts bargraph with a tooltip on hover of the the graph, and it should show another label on hover of the tooltip, but not working as expected.
I tried with onMouseover events but it is not working as expected, I wanted a bargraph with a tooltip on hover of the graph and on hover of the tooltip it should show additional details of the graph as another tooltip beside the first one.
import React, { useState } from "react";
import ReactDOM from "react-dom";
import ReactECharts from "echarts-for-react";
const BarChartUpdated = ({ data, label, categories }: any) => {
const [tooltipData, setTooltipData] = useState<{
x: number;
y: number;
details: string;
isVisible: boolean;
} | null>(null);
const generateColors = (categories: string[]) => {
const colorMap: Record<string, string> = {};
const colorPalette = [
"#5470C6",
"#91CC75",
"#EE6666",
"#FAC858",
"#73C0DE",
"#9A60B4",
"#EA7CCC",
];
categories.forEach((category, index) => {
if (!colorMap[category]) {
colorMap[category] = colorPalette[index % colorPalette.length];
}
});
return colorMap;
};
const categoryColors = generateColors(categories);
const sanitizedData = data.map((value: number) => (isNaN(value) ? 0 : value));
const total = sanitizedData.reduce(
(sum: number, value: number) => sum + value,
0,
);
const option = {
title: {
text: label,
},
tooltip: {
trigger: "axis",
formatter: (params: any) => {
return params
.map(
(item: any) =>
`<b>${item.name}</b></br> Count: ${item.value > 0 ? item.value : 0}`,
)
.join("<br/>");
},
},
toolbox: {
feature: {
saveAsImage: { show: true, title: "Save as Image" },
dataZoom: { show: true, title: "Zoom" },
},
},
xAxis: {
type: "category",
data: categories,
},
yAxis: {
type: "value",
},
series: [
{
type: "bar",
data: data.map((value: number, index: number) => ({
value,
itemStyle: {
color: categoryColors[categories[index]],
},
label: {
show: true,
position: "top",
formatter:
total <= 0 ? "0%" : `${Math.ceil((value / total) * 100)}%`,
},
})),
},
],
grid: {
left: "3%",
right: "4%",
bottom: "3%",
containLabel: true,
},
};
const handleMouseOver = (event: any) => {
if (event && event.data) {
const { name, value } = event.data;
const { offsetX, offsetY } = event.event;
setTooltipData({
x: offsetX,
y: offsetY,
details: `More details for ${name}: Count ${value}`,
isVisible: true,
});
}
};
const handleMouseOut = () => {
setTooltipData((prev) => (prev ? { ...prev, isVisible: false } : null));
};
const handleTooltipMouseEnter = () => {
setTooltipData((prev) => (prev ? { ...prev, isVisible: true } : null));
};
const handleTooltipMouseLeave = () => {
setTooltipData(null);
};
return (
<>
<ReactECharts
option={option}
style={{ height: 400, width: "100%" }}
onEvents={{
mouseover: handleMouseOver,
mouseout: handleMouseOut,
}}
/>
{tooltipData &&
ReactDOM.createPortal(
tooltipData.isVisible && (
<div
onMouseEnter={handleTooltipMouseEnter}
onMouseLeave={handleTooltipMouseLeave}
style={{
position: "fixed",
top: tooltipData.y,
left: tooltipData.x,
transform: "translate(-50%, -100%)",
background: "white",
border: "1px solid #ccc",
padding: "10px",
borderRadius: "4px",
boxShadow: "0 2px 4px rgba(0,0,0,0.2)",
zIndex: 1000,
}}
>
{tooltipData.details}
</div>
),
document.body,
)}
</>
);
};
export default BarChartUpdated;