import Chart from 'chart.js/auto'; import { useRef, useEffect, useState, } from 'react'; import './Chart.scss'; interface Props { chartData: { datasets: { data: number[]; count: number[]; backgroundColor: string[]; userLegendMailArray: string[]; }[]; labels: string[]; }; chartSize: string; legend: boolean; legendHeight: string; legendTitle: string; legendSubtitle: string; legendTitleColor: string; legendSubTitleValue: number; centerText: boolean; legeContainerWidth: string; isLegendUser: boolean; } const PieChart = ( { chartData, legend, chartSize, legendHeight, legendTitle, legendSubtitle, legendTitleColor, legendSubTitleValue, centerText, legeContainerWidth, isLegendUser, }: Props, ) => { const chartRef = useRef(null); const pdfRef = useRef(); const legendContainerRef = useRef(null); const currentCenterText = useRef(null); const maxLength = 12; const [tooltipPosition, setTooltipPosition] = useState({ y: 0 }); const [showTooltip, setShowTooltip] = useState(true); const pieChartTextPlugin = () => { const _active = chartRef.current._active; if (chartRef.current) { const ctx = chartRef.current.ctx; ctx.save(); ctx.font = '30px Arial'; if (ctx && _active && _active.length) { const index = _active[0]?.index; const value = chartRef.current.data.datasets[0].count[index]; const datasets = chartRef.current.data.datasets[0]; const textColors = datasets.backgroundColor[index % datasets.backgroundColor.length]; const labels = chartRef.current.data.labels; const label = labels[index].length > maxLength ? labels[index].substring(0, maxLength) + '...' : labels[index]; ctx.fillStyle = textColors; ctx.font = 'bold 45px Arial'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText( `${value}%`, chartRef?.current?.width / 2 + 15, chartRef?.current?.height / 2 - 15 ); ctx.font = ' 20px Arial'; ctx.fillText( `${label}`, chartRef.current.width / 2 + 15, chartRef.current.height / 2 + 20 ); } ctx.restore(); } }; const zeroCount = chartData.datasets[0].data.every( (element) => element === 0 ); const canvasCallback = (canvas: HTMLCanvasElement | null) => { if (!canvas) return; const ctx = canvas.getContext('2d'); if (!chartRef.current) { if (ctx) { chartRef.current = new Chart(ctx, { type: 'doughnut', data: chartData, options: { maintainAspectRatio: true, responsive: true, plugins: { legend: { display: false, }, tooltip: { enabled: false, }, }, layout: { padding: { left: 30, right: 0, top: 0, bottom: 0, }, }, }, plugins: [ { id: 'pieChartText', afterDatasetDraw: pieChartTextPlugin, }, ], }); } } }; useEffect(() => { if (chartRef.current) { if (zeroCount) { chartRef.current.data = { datasets: [ { data: [100], count: [0], backgroundColor: ['#E0E0E0'], }, ], labels: [''], }; } else { chartRef.current.data = chartData; } chartRef.current.update(); } currentCenterText.current = centerText; if (chartRef.current.options.plugins.pieChartText) { chartRef.current.options.plugins.pieChartText.enabled = centerText; } chartRef.current.update(); }, [chartData, centerText, zeroCount]); const renderLegend = () => { const datasets = chartData?.datasets[0]; const labels = chartData?.labels; const count = datasets?.count; const handleLegendItemHover = ( e: React.MouseEvent, index: number, isHovered: boolean ) => { if (isHovered) { const legendItem = e.target as HTMLElement; const legendItemRow = legendItem.getBoundingClientRect(); const legendContainerRect = legendContainerRef.current?.getBoundingClientRect(); if (legendItemRow && legendContainerRect) { const legendPosition = { y: legendContainerRect.bottom - legendItemRow.bottom, }; setTooltipPosition(legendPosition); } } else { setTooltipPosition({ y: 0 }); } if (chartRef.current) { const ctx = chartRef.current.ctx; if (ctx) { if (isHovered && centerText === true) { const value = datasets.count[index]; const label = labels[index].length > maxLength ? labels[index].substring(0, maxLength) + '...' : labels[index]; const textColor = datasets.backgroundColor[ index % datasets.backgroundColor.length ]; ctx.fillStyle = textColor; ctx.font = 'bold 45px Arial'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText( `${value}%`, chartRef.current.width / 2 + 15, chartRef.current.height / 2 - 15 ); ctx.font = '20px Arial'; ctx.fillText( `${label}`, chartRef.current.width / 2 + 15, chartRef.current.height / 2 + 20 ); } else { const centerX = chartRef.current.width / 2 + 15; const centerY = chartRef.current.height / 2; const innerRadius = 90; ctx.fillStyle = '#FFFFFF'; ctx.beginPath(); ctx.arc(centerX, centerY, innerRadius, 0, 2 * Math.PI); ctx.closePath(); ctx.fill(); } } } }; const handleScroll = () => { setShowTooltip(false); setTimeout(() => { setShowTooltip(true); }, 100); }; return (
{datasets?.data?.map((value, index) => (
handleLegendItemHover(e, index, true)} onMouseLeave={(e) => handleLegendItemHover(e, index, false)} > {' '} {labels[index]?.length > maxLength ? labels[index].substring(0, maxLength) + '...' : labels[index]} {count[index]}% {value} {showTooltip && labels[index]?.length > maxLength && (
{' '} {labels[index].length > 200 ? labels[index].substring(0, 200) + '...' : labels[index]}
{isLegendUser && (
{chartData?.datasets[0]?.userLegendMailArray[index]}
)}
)}
))}
); }; // useImperativeHandle(ref, () => ({ // downloadAsPDF, // })); // const downloadAsPDF = () => { // const legendElement = document.getElementById( // 'ff-chart-lagend' // ) as HTMLElement | null; // if (!legendElement) { // return; // } // const originalLegendHeight = legendElement.style.height; // legendElement.style.height = 'auto'; // const contentHeight = legendElement.scrollHeight + 100; // legendElement.style.height = `${contentHeight}px`; // const input = pdfRef.current; // html2canvas(input, { // height: contentHeight, // windowHeight: contentHeight, // }).then((canvas) => { // const imgData = canvas.toDataURL('image/png'); // const imgWidth = canvas.width; // const imgHeight = canvas.height; // const pdf = new jsPDF({ // orientation: 'landscape', // unit: 'px', // format: [imgWidth, imgHeight], // }); // const pageHeight = pdf.internal.pageSize.height; // let remainingHeight = imgHeight; // let currentPosition = 0; // while (remainingHeight > 0) { // pdf.addImage(imgData, 'PNG', 0, currentPosition, imgWidth, imgHeight); // currentPosition -= pageHeight; // remainingHeight -= pageHeight; // if (remainingHeight > 0) { // pdf.addPage([imgWidth, imgHeight]); // } // } // setTimeout(() => { // pdf.save('chart.pdf'); // legendElement.style.height = originalLegendHeight; // }, 200); // }); // }; return (
{legend === true && (
{legendTitle}
{legendSubtitle}: {''} {legendSubTitleValue}

{renderLegend()} {chartData?.labels?.length >= 6 && (
)}
)}
); } export default PieChart;