PozoStore/src/Components/Charts/PozoPublicPieChart.jsx

197 lines
7.4 KiB
JavaScript

import React, { useState, useEffect } from "react";
import "./PozoPublicPiechart.scss"
// Helper function to calculate the arcs for the donut chart
const calculateArcs = (data) => {
const total = data.reduce((acc, item) => acc + item.value, 0);
let cumulativePercentage = 0;
return data.map((item) => {
const percentage = (item.value / total) * 100;
const startAngle = cumulativePercentage;
const endAngle = cumulativePercentage + percentage;
cumulativePercentage = endAngle;
const largeArcFlag = percentage > 50 ? 1 : 0;
const outerRadius = 1; // Outer radius for the arc
const innerRadius = 0.7; // Inner radius for the hollow part
// Calculate the outer arc points
const startXOuter = outerRadius * Math.cos((2 * Math.PI * startAngle) / 100);
const startYOuter = outerRadius * Math.sin((2 * Math.PI * startAngle) / 100);
const endXOuter = outerRadius * Math.cos((2 * Math.PI * endAngle) / 100);
const endYOuter = outerRadius * Math.sin((2 * Math.PI * endAngle) / 100);
// Calculate the inner arc points
const startXInner = innerRadius * Math.cos((2 * Math.PI * startAngle) / 100);
const startYInner = innerRadius * Math.sin((2 * Math.PI * startAngle) / 100);
const endXInner = innerRadius * Math.cos((2 * Math.PI * endAngle) / 100);
const endYInner = innerRadius * Math.sin((2 * Math.PI * endAngle) / 100);
// Create the path for the arc (outer and inner)
const pathData = [
`M ${startXOuter} ${startYOuter}`, // Move to start of outer arc
`A ${outerRadius} ${outerRadius} 0 ${largeArcFlag} 1 ${endXOuter} ${endYOuter}`, // Outer arc
`L ${endXInner} ${endYInner}`, // Line to inner arc
`A ${innerRadius} ${innerRadius} 0 ${largeArcFlag} 0 ${startXInner} ${startYInner}`, // Inner arc
`Z`, // Close the path
].join(" ");
return {
pathData,
color: item.color,
value: item.value,
percentage: percentage.toFixed(2),
name: item.name,
date: item.date, // Add date to return object
};
});
};
const PieChart = ({ data }) => {
const [tooltip, setTooltip] = useState({ x: 0, y: 0, content: '', visible: false });
const [filter, setFilter] = useState(""); // State to hold the filter criteria
const [dateFilter, setDateFilter] = useState(""); // State to hold the date filter
const [animatedValues, setAnimatedValues] = useState(data.map(item => ({ ...item, animatedValue: 0 }))); // State for animated values
// Function to filter data
const filteredData = animatedValues.filter(item =>
item.name.toLowerCase().includes(filter.toLowerCase()) &&
(!dateFilter || item.date.includes(dateFilter)) // Filter by date
);
const handleMouseOver = (event, arc) => {
setTooltip({
x: event.clientX + 10,
y: event.clientY - 20,
content: `${arc.name}: ₹${arc.value} (${arc.percentage}%) on ${arc.date}`,
visible: true,
});
};
const handleMouseOut = () => {
setTooltip((prev) => ({ ...prev, visible: false }));
};
const arcs = calculateArcs(filteredData);
console.log(arcs, "yusgd");
// Animate values from 0 to actual value
useEffect(() => {
const animationDuration = 2000; // Animation duration in ms
const interval = 50; // Interval for the animation
const step = Math.floor(animationDuration / interval);
console.log("Animated Values:", animatedValues);
const newValues = animatedValues.map(item => ({
...item,
animatedValue: 0, // Start from 0
}));
let animationFrame = 0;
const intervalId = setInterval(() => {
if (animationFrame < step) {
setAnimatedValues(newValues.map(item => ({
...item,
animatedValue: Math.round((item.value / step) * (animationFrame + 0)), // Increment the value
})));
animationFrame++;
} else {
clearInterval(intervalId); // Stop the animation when complete
setAnimatedValues(newValues.map(item => ({ ...item, animatedValue: item.value }))); // Set to final value
}
}, interval);
return () => clearInterval(intervalId); // Cleanup interval on unmount
}, []);
return (
<div style={{ position: "relative",display: 'flex', alignItems: 'center', justifyContent: "space-around" , gap:"1rem"}}>
<div className="piechartsize">
{/* <input
type="text"
placeholder="Filter by name..."
value={filter}
onChange={(e) => setFilter(e.target.value)}
style={{ marginBottom: '1rem', padding: '8px', borderRadius: '4px', border: '1px solid #ccc' }}
/>
<input
type="text"
placeholder="Filter by date (YYYY-MM-DD)..."
value={dateFilter}
onChange={(e) => setDateFilter(e.target.value)}
style={{ marginBottom: '1rem', padding: '8px', borderRadius: '4px', border: '1px solid #ccc' }}
/> */}
<svg
viewBox="-1 -1 2 2"
className="loading-circle" // Add loading animation class here
style={{ transform: "rotate(-90deg)", width: "100%", height: "100%" }}
>
{arcs.map((arc, index) => (
<path
key={index}
d={arc.pathData}
fill={arc.color}
onMouseOver={(e) => handleMouseOver(e, arc)}
onMouseOut={handleMouseOut}
/>
))}
</svg>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.4rem' }}>
{arcs.map((arc, index) => (
<p key={index} style={{
display: 'flex',
alignItems: "center",
gap: '0.5rem',
textTransform: 'uppercase',
fontWeight: '600',
fontFamily: "Gilroy",
fontSize: '10.5px',
textWrap:"nowrap"
}}>
<div style={{ width: "6px", height: '6px', borderRadius: '60px', backgroundColor: arc.color, }}> </div>
{arc.name}
<p style={{width:'25px', color: '#007E1C',fontSize: '10.5px', }}> ₹{animatedValues[index]?.animatedValue}</p>
<p style={{ color: 'green',fontSize: '10.5px', }}> ({arc.percentage}%) </p>
</p>
))}
</div>
{tooltip.visible && (
<div
style={{
position: "absolute",
backgroundColor: "#23282D",
color: "#ecf0f1",
padding: "10px 15px",
borderRadius: "8px",
pointerEvents: "none",
zIndex: 10,
transform: "translate(-50%, -100%)",
fontSize: "14px",
fontFamily: "Arial, sans-serif",
}}
>
<div style={{
position: "absolute",
top: "100%",
left: "50%",
marginLeft: "-5px",
borderWidth: "5px",
borderStyle: "solid",
}} />
{tooltip.content}
</div>
)}
</div>
);
};
export default PieChart;