diff --git a/src/components/DynamicChart.tsx b/src/components/DynamicChart.tsx index 4651ade5..90d68e59 100644 --- a/src/components/DynamicChart.tsx +++ b/src/components/DynamicChart.tsx @@ -1,228 +1,273 @@ import { useState, useRef, useEffect } from 'react'; import { Chart } from 'react-chartjs-2'; -import { Chart as ChartJS, registerables } from 'chart.js'; +import { Chart as ChartJS, ChartOptions, registerables } from 'chart.js'; import annotationPlugin from 'chartjs-plugin-annotation'; ChartJS.register(...registerables, annotationPlugin); - const BarChartIcon = () => ( - - - - - - ); - - const PieChartIcon = () => ( - - - - - ); + + + + + +); - interface DynamicChartProps { - scores: number[], - scores_total: number, - scores_state: string, - quorum: number - } - -const DynamicChart = ({ scores, scores_total, scores_state, quorum }: DynamicChartProps) => { - const [chartType, setChartType] = useState<'bar' | 'pie'>('bar'); - const [legendPosition, setLegendPosition] = useState({ x: 0, y: 0 }); - const [showLegend, setShowLegend] = useState(false); - const containerRef = useRef(null); - - useEffect(() => { - const container = containerRef.current; - - const handleMouseMove = (event: MouseEvent) => { - if (container) { - const rect = container.getBoundingClientRect(); - const x = event.clientX - rect.left; - const y = event.clientY - rect.top; - - if (x >= 0 && x <= rect.width && y >= 0 && y <= rect.height) { - setShowLegend(true); - setLegendPosition({ x, y }); - } else { - setShowLegend(false); - } - } - }; +const PieChartIcon = () => ( + + + + +); - const handleMouseLeave = () => { - setShowLegend(false); - }; +interface DynamicChartProps { + scores: number[]; + scores_total: number; + scores_state: string; + quorum: number; +} - if (container) { - container.addEventListener('mousemove', handleMouseMove); - container.addEventListener('mouseleave', handleMouseLeave); - } +const DynamicChart = ({ + scores, + scores_total, + scores_state, + quorum, +}: DynamicChartProps) => { + const [chartType, setChartType] = useState<'bar' | 'pie'>('bar'); + const [legendPosition, setLegendPosition] = useState({ x: 0, y: 0 }); + const [showLegend, setShowLegend] = useState(false); + const containerRef = useRef(null); - return () => { - if (container) { - container.removeEventListener('mousemove', handleMouseMove); - container.removeEventListener('mouseleave', handleMouseLeave); - } - }; - }, []); - - if (scores_state !== 'final') return null; - - const labels = ['For', 'Against', 'Abstain']; - const colors = ['#4caf50', '#f44336', '#ff9800']; - - const data = { - labels: labels, - datasets: [ - { - data: scores, - backgroundColor: colors, - borderColor: 'black', - borderWidth: 2 - } - ] - }; + useEffect(() => { + const container = containerRef.current; - const options = { - responsive: true, - maintainAspectRatio: true, - plugins: { - legend: { - display: false, - }, - tooltip: { - enabled: false, - }, - annotation: chartType === 'bar' ? { - annotations: { - quorumLine: { - type: 'line', - xMin: quorum, - xMax: quorum, - borderColor: 'black', - borderWidth: 2, - borderDash: [6, 6] - } - } - } : {} - }, - ...(chartType === 'bar' ? { - indexAxis: 'y', - scales: { - x: { - beginAtZero: true, - title: { - display: true, - text: 'Amount', - color: 'black' - } - }, - y: { - title: { - display: false, - text: 'Vote Type', - color: 'black' - } - } - } - } : {}) + const handleMouseMove = (event: MouseEvent) => { + if (container) { + const rect = container.getBoundingClientRect(); + const x = event.clientX - rect.left; + const y = event.clientY - rect.top; + + if (x >= 0 && x <= rect.width && y >= 0 && y <= rect.height) { + setShowLegend(true); + setLegendPosition({ x, y }); + } else { + setShowLegend(false); + } + } }; - const legendStyle = { - position: 'absolute', - left: `${legendPosition.x + 10}px`, - top: `${legendPosition.y + 10}px`, - background: 'rgba(255, 255, 255, 0.95)', - border: '1px solid #ddd', - borderRadius: '4px', - padding: '10px', - pointerEvents: 'none', - zIndex: 1000, - fontSize: '16px', - boxShadow: '0 2px 5px rgba(0,0,0,0.2)', + const handleMouseLeave = () => { + setShowLegend(false); }; - const iconStyle = { - cursor: 'pointer', - padding: '5px', - borderRadius: '4px', - backgroundColor: 'rgba(255, 255, 255, 0.7)', - boxShadow: '0 1px 3px rgba(0,0,0,0.2)', - transition: 'background-color 0.3s', + if (container) { + container.addEventListener('mousemove', handleMouseMove); + container.addEventListener('mouseleave', handleMouseLeave); + } + + return () => { + if (container) { + container.removeEventListener('mousemove', handleMouseMove); + container.removeEventListener('mouseleave', handleMouseLeave); + } }; + }, []); + + if (scores_state !== 'final') return null; - return ( + const labels = ['For', 'Against', 'Abstain']; + const colors = ['#4caf50', '#f44336', '#ff9800']; + + const data = { + labels: labels, + datasets: [ + { + data: scores, + backgroundColor: colors, + borderColor: 'black', + borderWidth: 2, + }, + ], + }; + + const options: ChartOptions<'bar' | 'pie'> = { + responsive: true, + maintainAspectRatio: true, + plugins: { + legend: { + display: false, + }, + tooltip: { + enabled: false, + }, + annotation: + chartType === 'bar' + ? { + annotations: { + quorumLine: { + type: 'line', + xMin: quorum, + xMax: quorum, + borderColor: 'black', + borderWidth: 2, + borderDash: [6, 6], + }, + }, + } + : {}, + }, + ...(chartType === 'bar' + ? { + indexAxis: 'y', + scales: { + x: { + beginAtZero: true, + title: { + display: true, + text: 'Amount', + color: 'black', + }, + }, + y: { + title: { + display: false, + text: 'Vote Type', + color: 'black', + }, + }, + }, + } + : {}), + }; + + const iconStyle = { + cursor: 'pointer', + padding: '5px', + borderRadius: '4px', + backgroundColor: 'rgba(255, 255, 255, 0.7)', + boxShadow: '0 1px 3px rgba(0,0,0,0.2)', + transition: 'background-color 0.3s', + }; + + return ( +
+
+
setChartType('bar')} + style={{ + ...iconStyle, + color: chartType === 'bar' ? '#007bff' : '#666', + }} + title='Switch to Bar Chart' + > + +
setChartType('pie')} + style={{ + ...iconStyle, + color: chartType === 'pie' ? '#007bff' : '#666', + }} + title='Switch to Pie Chart' > -
-
setChartType('bar')} - style={{ ...iconStyle, color: chartType === 'bar' ? '#007bff' : '#666' }} - title="Switch to Bar Chart" - > - -
-
setChartType('pie')} - style={{ ...iconStyle, color: chartType === 'pie' ? '#007bff' : '#666' }} - title="Switch to Pie Chart" - > - -
-
- - {showLegend && ( -
- - - {labels.map((label, index) => ( - - - - - ))} - - - - - - - - - - - - -
- - {label}: - - {scores[index]} ({((scores[index] / scores_total) * 100).toFixed(2)}%) -

Total:{scores_total}
Quorum:{quorum}
-
- )} +
- ); +
+ + {showLegend && ( +
+ + + {labels.map((label, index) => ( + + + + + ))} + + + + + + + + + + + + +
+ + {label}: + + {scores[index]} ( + {((scores[index] / scores_total) * 100).toFixed(2)}%) +
+
+
Total:{scores_total}
Quorum:{quorum}
+
+ )} +
+ ); }; -export default DynamicChart; \ No newline at end of file +export default DynamicChart;