// import Chart from 'chart.js/auto'; import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js'; import { useRef, useEffect } from 'react'; import './Chart.scss'; interface Props { chartData: { labels: string[]; datasets: { data: number[]; toolTipMailArray: string[]; count: number[]; }[]; }; chartHeight: string; chartWidth: string; toolTipText: string; xAxisLabel: string; yAxisLabel: string; } const BarChart = ({ chartData, chartHeight, chartWidth, toolTipText, xAxisLabel, yAxisLabel, }: Props) => { const dynamicTooltipTextRef = useRef(toolTipText); useEffect(() => { dynamicTooltipTextRef.current = toolTipText; }, [toolTipText]); const calculatedWidth = `${chartData?.labels?.length * 10}vw`; const containerExtend = { height: chartHeight, width: calculatedWidth, }; const containerBody = { height: chartHeight, width: chartWidth, }; const chartRef1 = useRef(null); const chartRef2 = useRef(null); const graphRef = useRef(); const renderExternalTooltip = (context: any) => { let tooltipEl = document.getElementById('chartjs-tooltip'); if (!tooltipEl) { tooltipEl = document.createElement('div'); tooltipEl.id = 'chartjs-tooltip'; document.body.appendChild(tooltipEl); } const tooltipModel = context.tooltip; if (tooltipModel.opacity === 0) { tooltipEl.style.opacity = '0'; return; } if (tooltipModel.body) { const { dataPoints } = tooltipModel; tooltipEl.innerHTML = ''; dataPoints.forEach(({ datasetIndex, dataIndex }: any) => { const dataset = chartData.datasets[datasetIndex]; const label = chartData.labels[dataIndex]; const data = dataset.data[dataIndex]; const count = dataset?.count[dataIndex]; const toolTipMail = dataset.toolTipMailArray[dataIndex]; if (toolTipMail && toolTipMail.length > 0) { tooltipEl.innerHTML += `
${label}
${toolTipMail}
${dynamicTooltipTextRef.current}: ${data} (${count}%)
`; } else { tooltipEl.innerHTML += `
${label}
${dynamicTooltipTextRef.current}: ${data} (${count}%)
`; } }); } const position = context.chart.canvas.getBoundingClientRect(); const dataIndex = context.tooltip.dataPoints[0]?.dataIndex; const isLastBar = dataIndex === chartData.labels.length - 1; const tooltipX = isLastBar ? position.left + tooltipModel.caretX - tooltipEl.offsetWidth - 5 : position.left + tooltipModel.caretX; const tooltipY = position.top + tooltipModel.caretY - 50; tooltipEl.style.position = 'absolute'; tooltipEl.style.left = `${tooltipX}px`; tooltipEl.style.top = `${tooltipY}px`; tooltipEl.style.opacity = '1'; tooltipEl.style.backgroundColor = '#FFFFFF'; tooltipEl.style.border = '1px solid #C4C3C3'; tooltipEl.style.borderRadius = '5px'; tooltipEl.style.boxShadow = '0 2px 4px rgba(0,0,0,0.1)'; tooltipEl.style.padding = '10px'; tooltipEl.style.pointerEvents = 'none'; }; const zeroCount = chartData.datasets[0].data.every( (element) => element === 0 ); const canvasCallback = (canvas: HTMLCanvasElement) => { if (!canvas) return; const ctx = canvas.getContext('2d'); const gracePercent = zeroCount ? '0%' : '5%'; const yAxisRange = zeroCount ? { min: 0, max: 100 } : { beginAtZero: true }; if (chartRef1.current) { chartRef1.current.destroy(); } if (ctx) { chartRef1.current = new ChartJS(ctx, { type: 'bar', data: chartData, options: { maintainAspectRatio: false, layout: { padding: { top: 10, }, }, scales: { x: { ticks: { callback: (value) => { const label = chartRef1.current?.scales['x']?.getLabelForValue(value); return String(label).substring(0, 10); }, }, grid: { display: false, }, title: { display: true, text: '', font: { size: 13, }, }, offset: true, }, y: { ...yAxisRange, grace: gracePercent, ticks: { display: false, }, grid: { drawTicks: false, }, }, }, plugins: { legend: { display: false, }, tooltip: { enabled: false, external: renderExternalTooltip, }, }, }, }); } }; const canvasCallback2 = (canvas: HTMLCanvasElement | null) => { let paddingValue = chartData?.labels.length > 10 ? 56 : 56; if (!canvas) return; const ctx = canvas.getContext('2d'); const gracePercent = zeroCount ? '0%' : '5%'; const yAxisRange = zeroCount ? { min: 0, max: 100 } : { beginAtZero: true }; if (chartRef2.current) { chartRef2.current.destroy(); } if (ctx) { chartRef2.current = new ChartJS(ctx, { type: 'bar', data: chartData, options: { maintainAspectRatio: false, layout: { padding: { bottom: paddingValue, }, }, scales: { x: { ticks: { display: false, }, grid: { drawTicks: false, }, }, y: { ...yAxisRange, grace: gracePercent, afterFit: (ctx) => { ctx.width = 42; }, title: { display: true, text: '', font: { size: 13, }, padding: { top: -1, }, }, }, }, plugins: { legend: { display: false, }, }, }, }); } }; useEffect(() => { if (chartRef1.current) { chartRef1.current.data = chartData; chartRef1.current.update(); chartRef1.current.options.plugins.tooltip.external = renderExternalTooltip; } if (chartRef2.current) { chartRef2.current.data = chartData; chartRef2.current.update(); } if (chartRef2.current) { chartRef2.current.options.scales.y.title.text = yAxisLabel; chartRef2.current.update(); } if (chartRef1.current) { chartRef1.current.options.scales.x.title.text = xAxisLabel; chartRef1.current.update(); } return () => {}; }, [chartData, toolTipText, xAxisLabel, yAxisLabel]); return (
6 ? containerExtend : containerBody } >
); }; export default BarChart;