2022-06-17 22:37:05 -04:00
|
|
|
import { Group } from "@visx/group";
|
|
|
|
import Pie, { ProvidedProps } from "@visx/shape/lib/shapes/Pie";
|
2022-08-09 18:00:22 -04:00
|
|
|
import { Text } from "@visx/text";
|
2022-06-18 22:50:08 -04:00
|
|
|
import React from "react";
|
2022-06-17 22:37:05 -04:00
|
|
|
|
|
|
|
import styles from "./PieChart.module.css";
|
|
|
|
|
|
|
|
interface PieChartProps {
|
|
|
|
data: PieChartData[];
|
2022-08-09 18:00:22 -04:00
|
|
|
/** Width of the entire graph, including labels, in pixels. */
|
2022-06-17 22:37:05 -04:00
|
|
|
width: number;
|
2022-08-09 18:00:22 -04:00
|
|
|
/** Width of the outer ring of labels, in pixels. */
|
2022-06-18 22:55:05 -04:00
|
|
|
labelWidth: number;
|
2022-08-09 18:00:22 -04:00
|
|
|
/** Distance between pie slices, in pixels */
|
2022-07-06 19:44:48 -04:00
|
|
|
padRadius?: number;
|
2022-08-09 18:00:22 -04:00
|
|
|
/** Distance of gap in center of pie graph, in pixels */
|
2022-07-06 19:44:48 -04:00
|
|
|
innerRadius?: number;
|
2022-08-09 18:00:22 -04:00
|
|
|
/** Font size of text inside the pie, in pixels*/
|
|
|
|
pieTextSize?: number;
|
|
|
|
/** Font size of labels outside the pie, in pixels */
|
|
|
|
labelTextSize?: number;
|
|
|
|
/** X-axis offset of the pie text, in pixels */
|
|
|
|
pieTextXOffset?: number;
|
|
|
|
/** Y-axis offset of the pie text, in pixels */
|
|
|
|
pieTextYOffset?: number;
|
2022-06-17 22:37:05 -04:00
|
|
|
className?: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface PieChartData {
|
|
|
|
category: string;
|
|
|
|
value: number;
|
|
|
|
}
|
|
|
|
|
2022-07-06 19:44:48 -04:00
|
|
|
export function PieChart({
|
2022-08-09 18:00:22 -04:00
|
|
|
data,
|
2022-07-06 19:44:48 -04:00
|
|
|
width,
|
|
|
|
labelWidth,
|
|
|
|
padRadius = width * 0.35,
|
|
|
|
innerRadius = width * 0.015,
|
2022-08-09 18:00:22 -04:00
|
|
|
pieTextSize = 40,
|
|
|
|
labelTextSize = 40,
|
|
|
|
pieTextXOffset = 0,
|
|
|
|
pieTextYOffset = 10,
|
|
|
|
className,
|
2022-07-06 19:44:48 -04:00
|
|
|
}: PieChartProps) {
|
2022-06-18 22:55:05 -04:00
|
|
|
const pieWidth = width * 0.5 - labelWidth;
|
2022-06-17 22:37:05 -04:00
|
|
|
return (
|
2022-08-09 18:00:22 -04:00
|
|
|
<svg className={className} width={width} height={width}>
|
2022-06-18 22:35:39 -04:00
|
|
|
<Group top={width * 0.5} left={width * 0.5}>
|
2022-06-17 22:37:05 -04:00
|
|
|
<Pie
|
2022-08-09 18:00:22 -04:00
|
|
|
data={data}
|
2022-06-17 22:37:05 -04:00
|
|
|
pieValue={(d: PieChartData) => d.value}
|
2022-06-18 22:35:39 -04:00
|
|
|
cornerRadius={10}
|
|
|
|
padAngle={0.075}
|
2022-07-06 19:44:48 -04:00
|
|
|
padRadius={padRadius}
|
|
|
|
innerRadius={innerRadius}
|
2022-06-18 22:35:39 -04:00
|
|
|
outerRadius={pieWidth}
|
2022-06-17 22:37:05 -04:00
|
|
|
>
|
2022-08-09 18:00:22 -04:00
|
|
|
{(pie) => (
|
|
|
|
<PieSlice
|
|
|
|
{...pie}
|
|
|
|
isLabel={false}
|
|
|
|
pieTextSize={pieTextSize}
|
|
|
|
labelTextSize={labelTextSize}
|
|
|
|
pieTextXOffset={pieTextXOffset}
|
|
|
|
pieTextYOffset={pieTextYOffset}
|
|
|
|
/>
|
|
|
|
)}
|
2022-06-18 22:35:39 -04:00
|
|
|
</Pie>
|
|
|
|
<Pie
|
2022-08-09 18:00:22 -04:00
|
|
|
data={data}
|
2022-06-18 22:35:39 -04:00
|
|
|
pieValue={(d: PieChartData) => d.value}
|
|
|
|
innerRadius={pieWidth}
|
|
|
|
outerRadius={width * 0.5}
|
|
|
|
>
|
2022-08-09 18:00:22 -04:00
|
|
|
{(pie) => (
|
|
|
|
<PieSlice
|
|
|
|
{...pie}
|
|
|
|
isLabel={true}
|
|
|
|
pieTextSize={pieTextSize}
|
|
|
|
labelTextSize={labelTextSize}
|
|
|
|
pieTextXOffset={pieTextXOffset}
|
|
|
|
pieTextYOffset={pieTextYOffset}
|
|
|
|
/>
|
|
|
|
)}
|
2022-06-17 22:37:05 -04:00
|
|
|
</Pie>
|
|
|
|
</Group>
|
|
|
|
</svg>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-08-09 18:00:22 -04:00
|
|
|
type PieSliceProps<PieChartData> = ProvidedProps<PieChartData> & {
|
2022-06-18 22:35:39 -04:00
|
|
|
isLabel: boolean;
|
2022-08-09 18:00:22 -04:00
|
|
|
pieTextSize: number;
|
|
|
|
labelTextSize: number;
|
|
|
|
pieTextXOffset: number;
|
|
|
|
pieTextYOffset: number;
|
2022-06-18 22:35:39 -04:00
|
|
|
};
|
2022-06-17 22:37:05 -04:00
|
|
|
|
2022-08-09 18:00:22 -04:00
|
|
|
export function PieSlice({
|
|
|
|
path,
|
|
|
|
arcs,
|
|
|
|
isLabel,
|
|
|
|
pieTextSize,
|
|
|
|
labelTextSize,
|
|
|
|
pieTextXOffset,
|
|
|
|
pieTextYOffset,
|
|
|
|
}: PieSliceProps<PieChartData>) {
|
2022-06-18 22:35:39 -04:00
|
|
|
return (
|
|
|
|
<>
|
2022-08-09 18:00:22 -04:00
|
|
|
{arcs.map((arc) => {
|
|
|
|
const [centroidX, centroidY] = path.centroid(arc);
|
|
|
|
const pathArc = path(arc) as string;
|
2022-06-17 22:37:05 -04:00
|
|
|
|
2022-06-18 22:35:39 -04:00
|
|
|
return (
|
2022-08-09 18:00:22 -04:00
|
|
|
<Group className={styles.group} key={`arc-${arc.data.category}`}>
|
2022-06-18 22:35:39 -04:00
|
|
|
<path
|
|
|
|
className={isLabel ? styles.labelPath : styles.piePath}
|
|
|
|
d={pathArc}
|
|
|
|
/>
|
2022-08-09 18:00:22 -04:00
|
|
|
<Text
|
2022-06-18 22:35:39 -04:00
|
|
|
className={isLabel ? styles.labelText : styles.pieText}
|
2022-08-09 18:00:22 -04:00
|
|
|
x={isLabel ? centroidX : centroidX + pieTextXOffset}
|
|
|
|
y={isLabel ? centroidY : centroidY + pieTextYOffset}
|
2022-06-18 22:35:39 -04:00
|
|
|
textAnchor="middle"
|
2022-08-09 18:00:22 -04:00
|
|
|
fontSize={isLabel ? labelTextSize : pieTextSize}
|
2022-06-18 22:35:39 -04:00
|
|
|
>
|
2022-07-06 19:56:06 -04:00
|
|
|
{isLabel ? `${arc.data.category}` : `${arc.data.value}%`}
|
2022-08-09 18:00:22 -04:00
|
|
|
</Text>
|
|
|
|
</Group>
|
2022-06-18 22:35:39 -04:00
|
|
|
);
|
|
|
|
})}
|
|
|
|
</>
|
|
|
|
);
|
2022-06-17 22:37:05 -04:00
|
|
|
}
|