|
|
|
@ -1,4 +1,5 @@ |
|
|
|
|
import { Group } from "@visx/group"; |
|
|
|
|
import { Arc } from "@visx/shape"; |
|
|
|
|
import Pie, { ProvidedProps } from "@visx/shape/lib/shapes/Pie"; |
|
|
|
|
import React, { useState } from "react"; |
|
|
|
|
|
|
|
|
@ -7,13 +8,7 @@ import styles from "./PieChart.module.css"; |
|
|
|
|
interface PieChartProps { |
|
|
|
|
data: PieChartData[]; |
|
|
|
|
width: number; |
|
|
|
|
height: number; |
|
|
|
|
margin: { |
|
|
|
|
top: number; |
|
|
|
|
bottom: number; |
|
|
|
|
left: number; |
|
|
|
|
right: number; |
|
|
|
|
}; |
|
|
|
|
textPadding: number; |
|
|
|
|
className?: string; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -22,19 +17,31 @@ interface PieChartData { |
|
|
|
|
value: number; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export function PieChart(props: PieChartProps) { |
|
|
|
|
export function PieChart({ width, textPadding, ...props }: PieChartProps) { |
|
|
|
|
const pieWidth = width * 0.5 - textPadding; |
|
|
|
|
return ( |
|
|
|
|
<svg className={props.className} width={props.width} height={props.height}> |
|
|
|
|
<Group top={props.margin.top} left={props.margin.left}> |
|
|
|
|
<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} |
|
|
|
|
outerRadius={100} |
|
|
|
|
cornerRadius={5} |
|
|
|
|
padAngle={0.1} |
|
|
|
|
cornerRadius={10} |
|
|
|
|
padAngle={0.075} |
|
|
|
|
padRadius={width * 0.7} |
|
|
|
|
innerRadius={width * 0.03} |
|
|
|
|
outerRadius={pieWidth} |
|
|
|
|
> |
|
|
|
|
{(pie) => <PieSlice {...pie} />} |
|
|
|
|
{(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> |
|
|
|
@ -42,23 +49,34 @@ export function PieChart(props: PieChartProps) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// path, arcs, pie
|
|
|
|
|
type PieSliceProps<PieChartData> = ProvidedProps<PieChartData>; |
|
|
|
|
type PieSlicesProps<PieChartData> = ProvidedProps<PieChartData> & { |
|
|
|
|
isLabel: boolean; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
export function PieSlice(props: PieSliceProps<PieChartData>) { |
|
|
|
|
return props.arcs.map((arc) => { |
|
|
|
|
const [centroidX, centroidY] = props.path.centroid(arc); |
|
|
|
|
const pathArc = props.path(arc); |
|
|
|
|
export function PieSlices({ isLabel, ...props }: PieSlicesProps<PieChartData>) { |
|
|
|
|
return ( |
|
|
|
|
<> |
|
|
|
|
{props.arcs.map((arc) => { |
|
|
|
|
const [centroidX, centroidY] = props.path.centroid(arc); |
|
|
|
|
const pathArc = props.path(arc); |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<g key={`arc-${arc.data.category}`} className={styles.group}> |
|
|
|
|
<path className={styles.path} d={pathArc} /> |
|
|
|
|
<text |
|
|
|
|
className={styles.text} |
|
|
|
|
x={centroidX} |
|
|
|
|
y={centroidY} |
|
|
|
|
textAnchor="middle" |
|
|
|
|
>{`${arc.data.value}%`}</text> |
|
|
|
|
</g> |
|
|
|
|
); |
|
|
|
|
}); |
|
|
|
|
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={centroidX} |
|
|
|
|
y={centroidY} |
|
|
|
|
textAnchor="middle" |
|
|
|
|
> |
|
|
|
|
{isLabel ? `${arc.data.category}` : `${arc.data.value}%`} |
|
|
|
|
</text> |
|
|
|
|
</g> |
|
|
|
|
); |
|
|
|
|
})} |
|
|
|
|
</> |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|