89 lines
2.3 KiB
TypeScript
89 lines
2.3 KiB
TypeScript
import { Group } from "@visx/group";
|
|
import Pie, { ProvidedProps } from "@visx/shape/lib/shapes/Pie";
|
|
import React from "react";
|
|
|
|
import styles from "./PieChart.module.css";
|
|
|
|
interface PieChartProps {
|
|
data: PieChartData[];
|
|
width: number;
|
|
labelWidth: number;
|
|
padRadius?: number;
|
|
innerRadius?: number;
|
|
className?: string;
|
|
}
|
|
|
|
interface PieChartData {
|
|
category: string;
|
|
value: number;
|
|
}
|
|
|
|
export function PieChart({
|
|
width,
|
|
labelWidth,
|
|
padRadius = width * 0.35,
|
|
innerRadius = width * 0.015,
|
|
...props
|
|
}: PieChartProps) {
|
|
const pieWidth = width * 0.5 - labelWidth;
|
|
return (
|
|
<svg className={props.className} width={width} height={width}>
|
|
<Group top={width * 0.5} left={width * 0.5}>
|
|
<Pie
|
|
data={props.data}
|
|
fill="aqua"
|
|
pieValue={(d: PieChartData) => d.value}
|
|
cornerRadius={10}
|
|
padAngle={0.075}
|
|
padRadius={padRadius}
|
|
innerRadius={innerRadius}
|
|
outerRadius={pieWidth}
|
|
>
|
|
{(pie) => <PieSlices {...pie} isLabel={false} />}
|
|
</Pie>
|
|
<Pie
|
|
data={props.data}
|
|
fill="rgb(37, 45, 65)"
|
|
pieValue={(d: PieChartData) => d.value}
|
|
innerRadius={pieWidth}
|
|
outerRadius={width * 0.5}
|
|
>
|
|
{(pie) => <PieSlices {...pie} isLabel={true} />}
|
|
</Pie>
|
|
</Group>
|
|
</svg>
|
|
);
|
|
}
|
|
|
|
type PieSlicesProps<PieChartData> = ProvidedProps<PieChartData> & {
|
|
isLabel: boolean;
|
|
};
|
|
|
|
export function PieSlices({ isLabel, ...props }: PieSlicesProps<PieChartData>) {
|
|
return (
|
|
<>
|
|
{props.arcs.map((arc) => {
|
|
const [centroidX, centroidY] = props.path.centroid(arc);
|
|
const pathArc = props.path(arc) as string;
|
|
|
|
return (
|
|
<g className={styles.group} key={`arc-${arc.data.category}`}>
|
|
<path
|
|
className={isLabel ? styles.labelPath : styles.piePath}
|
|
d={pathArc}
|
|
/>
|
|
<text
|
|
className={isLabel ? styles.labelText : styles.pieText}
|
|
x={isLabel ? centroidX : centroidX}
|
|
y={isLabel ? centroidY : centroidY + 10}
|
|
textAnchor="middle"
|
|
>
|
|
{isLabel ? `${arc.data.category}` : `${arc.data.value}%`}
|
|
</text>
|
|
</g>
|
|
);
|
|
})}
|
|
</>
|
|
);
|
|
}
|