Initial commit
This commit is contained in:
107
components/simple-pie-chart.tsx
Normal file
107
components/simple-pie-chart.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
"use client"
|
||||
|
||||
interface Stats {
|
||||
no_report: number
|
||||
in_shelter: number
|
||||
not_in_shelter: number
|
||||
no_alarm: number
|
||||
}
|
||||
|
||||
interface SimplePieChartProps {
|
||||
stats: Stats
|
||||
onCategoryClick: (category: string, categoryName: string) => void
|
||||
}
|
||||
|
||||
export function SimplePieChart({ stats, onCategoryClick }: SimplePieChartProps) {
|
||||
const data = [
|
||||
{ name: "לא דיווחו", value: stats?.no_report || 0, color: "#ef4444", category: "no_report" },
|
||||
{ name: "במקלט/חדר מוגן", value: stats?.in_shelter || 0, color: "#22c55e", category: "in_shelter" },
|
||||
{ name: "לא במקלט", value: stats?.not_in_shelter || 0, color: "#f97316", category: "not_in_shelter" },
|
||||
{ name: "אין אזעקה", value: stats?.no_alarm || 0, color: "#3b82f6", category: "no_alarm" },
|
||||
]
|
||||
|
||||
const total = data.reduce((sum, item) => sum + item.value, 0)
|
||||
|
||||
if (total === 0) {
|
||||
return (
|
||||
<div className="h-80 flex items-center justify-center">
|
||||
<div className="text-center text-gray-500">
|
||||
<div className="text-6xl mb-4">📊</div>
|
||||
<p className="text-lg font-semibold">אין נתונים להצגה</p>
|
||||
<p className="text-sm">הוסף משתמשים כדי לראות סטטיסטיקות</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
let currentAngle = 0
|
||||
|
||||
return (
|
||||
<div className="h-80 flex flex-col items-center justify-center">
|
||||
<div className="relative w-48 h-48 mb-4">
|
||||
<svg width="192" height="192" className="transform -rotate-90">
|
||||
{data.map((item, index) => {
|
||||
if (item.value === 0) return null
|
||||
|
||||
const percentage = (item.value / total) * 100
|
||||
const angle = (item.value / total) * 360
|
||||
const startAngle = currentAngle
|
||||
const endAngle = currentAngle + angle
|
||||
|
||||
const startAngleRad = (startAngle * Math.PI) / 180
|
||||
const endAngleRad = (endAngle * Math.PI) / 180
|
||||
|
||||
const largeArcFlag = angle > 180 ? 1 : 0
|
||||
|
||||
const x1 = 96 + 80 * Math.cos(startAngleRad)
|
||||
const y1 = 96 + 80 * Math.sin(startAngleRad)
|
||||
const x2 = 96 + 80 * Math.cos(endAngleRad)
|
||||
const y2 = 96 + 80 * Math.sin(endAngleRad)
|
||||
|
||||
const pathData = [`M 96 96`, `L ${x1} ${y1}`, `A 80 80 0 ${largeArcFlag} 1 ${x2} ${y2}`, `Z`].join(" ")
|
||||
|
||||
currentAngle += angle
|
||||
|
||||
return (
|
||||
<path
|
||||
key={index}
|
||||
d={pathData}
|
||||
fill={item.color}
|
||||
stroke="white"
|
||||
strokeWidth="2"
|
||||
className="cursor-pointer hover:opacity-80 transition-opacity"
|
||||
onClick={() => onCategoryClick(item.category, item.name)}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</svg>
|
||||
|
||||
{/* Center text */}
|
||||
<div className="absolute inset-0 flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="text-2xl font-bold">{total}</div>
|
||||
<div className="text-xs text-gray-500">סה"כ</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Legend */}
|
||||
<div className="grid grid-cols-2 gap-2 text-sm">
|
||||
{data
|
||||
.filter((item) => item.value > 0)
|
||||
.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center gap-2 cursor-pointer hover:bg-gray-100 p-1 rounded"
|
||||
onClick={() => onCategoryClick(item.category, item.name)}
|
||||
>
|
||||
<div className="w-3 h-3 rounded-full" style={{ backgroundColor: item.color }} />
|
||||
<span className="text-xs">
|
||||
{item.name}: {item.value}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user