import { Group } from "@visx/group"; import Pie, { ProvidedProps } from "@visx/shape/lib/shapes/Pie"; import { Text } from "@visx/text"; import React from "react"; import styles from "./PieChart.module.css"; interface PieChartProps { data: PieChartData[]; /** Width of the entire graph, including labels, in pixels. */ width: number; /** Width of the outer ring of labels, in pixels. Label text may be cut off if specified value is too small. */ labelWidth: number; /** Distance between pie slices, in pixels. */ padRadius?: number; /** Distance of gap in center of pie graph, in pixels. */ innerRadius?: number; /** Font size of text inside the pie, in pixels. */ pieTextSize?: number; /** X-axis offset of the pie text, in pixels. */ pieTextXOffset?: number; /** Y-axis offset of the pie text, in pixels. */ pieTextYOffset?: number; /** Accessor function to get value to display as pie text from datum. */ getPieDisplayValueFromDatum?: (datum: PieChartData) => string; /** Font size of labels outside the pie, in pixels. */ labelTextSize?: number; /** X-axis offset of the label text, in pixels. */ labelTextXOffset?: number; /** Y-axis offset of the label text, in pixels. */ labelTextYOffset?: number; /** Accessor function to get value to display as label text from datum. */ getLabelDisplayValueFromDatum?: (datum: PieChartData) => string; className?: string; } interface PieChartData { category: string; value: number; } export function PieChart({ data, width, labelWidth, padRadius = width * 0.35, innerRadius = width * 0.015, pieTextSize = 40, pieTextXOffset = 0, pieTextYOffset = 10, getPieDisplayValueFromDatum = (datum: PieChartData) => `${datum.value}%`, labelTextSize = 40, labelTextXOffset = 0, labelTextYOffset = 0, getLabelDisplayValueFromDatum = (datum: PieChartData) => `${datum.category}`, className, }: PieChartProps) { const pieWidth = width * 0.5 - labelWidth; return ( d.value} cornerRadius={10} padAngle={0.075} padRadius={padRadius} innerRadius={innerRadius} outerRadius={pieWidth} > {(pie) => ( )} d.value} innerRadius={pieWidth} outerRadius={width * 0.5} > {(pie) => ( )} ); } type PieSliceProps = ProvidedProps & { pieTextSize: number; pieTextXOffset: number; pieTextYOffset: number; getPieDisplayValueFromDatum: (datum: PieChartData) => string; }; export function PieSlice({ path, arcs, pieTextSize, pieTextXOffset, pieTextYOffset, getPieDisplayValueFromDatum, }: PieSliceProps) { return ( <> {arcs.map((arc) => { const [centroidX, centroidY] = path.centroid(arc); const pathArc = path(arc) as string; return ( {`${getPieDisplayValueFromDatum(arc.data)}`} ); })} ); } type PieSliceLabelProps = ProvidedProps & { labelTextSize: number; labelTextXOffset: number; labelTextYOffset: number; getLabelDisplayValueFromDatum: (datum: PieChartData) => string; }; export function PieSliceLabel({ path, arcs, labelTextSize, labelTextXOffset, labelTextYOffset, getLabelDisplayValueFromDatum, }: PieSliceLabelProps) { return ( <> {arcs.map((arc) => { const [centroidX, centroidY] = path.centroid(arc); const pathArc = path(arc) as string; return ( {`${getLabelDisplayValueFromDatum(arc.data)}`} ); })} ); }