Change Pie Char to use tooltips
continuous-integration/drone/push Build is passing Details

This commit is contained in:
e26chiu 2022-12-16 16:24:23 -05:00
parent 50a637755b
commit 074828d7ae
1 changed files with 113 additions and 97 deletions

View File

@ -1,8 +1,13 @@
import { localPoint } from "@visx/event";
import { Group } from "@visx/group"; import { Group } from "@visx/group";
import { Point } from "@visx/point";
import Pie, { ProvidedProps } from "@visx/shape/lib/shapes/Pie"; import Pie, { ProvidedProps } from "@visx/shape/lib/shapes/Pie";
import { Text } from "@visx/text"; import { Text } from "@visx/text";
import { withTooltip } from "@visx/tooltip";
import React from "react"; import React from "react";
import { TooltipWrapper } from "./TooltipWrapper";
import styles from "./PieChart.module.css"; import styles from "./PieChart.module.css";
interface PieChartProps { interface PieChartProps {
@ -39,105 +44,116 @@ interface PieChartData {
value: number; value: number;
} }
export function PieChart({ export const PieChart = withTooltip<PieChartProps>(
data, ({
width, data,
labelWidth, width,
padRadius = width * 0.35, labelWidth,
innerRadius = width * 0.015, padRadius = width * 0.35,
pieTextSize = 40, innerRadius = width * 0.015,
pieTextXOffset = 0, pieTextSize = 40,
pieTextYOffset = 10, pieTextXOffset = 0,
getPieDisplayValueFromDatum = (datum: PieChartData) => `${datum.value}%`, pieTextYOffset = 10,
labelTextSize = 40, getPieDisplayValueFromDatum = (datum: PieChartData) => `${datum.value}%`,
labelTextXOffset = 0, labelTextSize = 40,
labelTextYOffset = 0, labelTextXOffset = 0,
getLabelDisplayValueFromDatum = (datum: PieChartData) => `${datum.category}`, labelTextYOffset = 0,
className, getLabelDisplayValueFromDatum = (datum: PieChartData) =>
}: PieChartProps) { `${datum.category}`,
const pieWidth = width * 0.5 - labelWidth; className,
return ( tooltipOpen,
<svg className={className} width={width} height={width}> tooltipLeft,
<Group top={width * 0.5} left={width * 0.5}> tooltipTop,
<Pie tooltipData,
data={data} hideTooltip,
pieValue={(d: PieChartData) => d.value} showTooltip,
cornerRadius={10} }) => {
padAngle={0.075} const pieWidth = width * 0.5 - labelWidth;
padRadius={padRadius} return (
innerRadius={innerRadius} <div>
outerRadius={pieWidth} <svg className={className} width={width} height={width}>
> <Group top={width * 0.5} left={width * 0.5}>
{(pie) => ( <Pie
<PieSlice data={data}
{...pie} pieValue={(d: PieChartData) => d.value}
pieTextSize={pieTextSize} cornerRadius={10}
pieTextXOffset={pieTextXOffset} padAngle={0.075}
pieTextYOffset={pieTextYOffset} padRadius={padRadius}
getPieDisplayValueFromDatum={getPieDisplayValueFromDatum} innerRadius={innerRadius}
/> outerRadius={pieWidth}
)}
</Pie>
<Pie
data={data}
pieValue={(d: PieChartData) => d.value}
innerRadius={pieWidth}
outerRadius={width * 0.5}
>
{(pie) => (
<PieSliceLabel
{...pie}
labelTextSize={labelTextSize}
labelTextXOffset={labelTextXOffset}
labelTextYOffset={labelTextYOffset}
getLabelDisplayValueFromDatum={getLabelDisplayValueFromDatum}
/>
)}
</Pie>
</Group>
</svg>
);
}
type PieSliceProps<PieChartData> = ProvidedProps<PieChartData> & {
pieTextSize: number;
pieTextXOffset: number;
pieTextYOffset: number;
getPieDisplayValueFromDatum: (datum: PieChartData) => string;
};
export function PieSlice({
path,
arcs,
pieTextSize,
pieTextXOffset,
pieTextYOffset,
getPieDisplayValueFromDatum,
}: PieSliceProps<PieChartData>) {
return (
<>
{arcs.map((arc) => {
const [centroidX, centroidY] = path.centroid(arc);
const pathArc = path(arc) as string;
return (
<Group className={styles.group} key={`arc-${arc.data.category}`}>
<path className={styles.piePath} d={pathArc} />
<Text
className={styles.pieText}
x={centroidX + pieTextXOffset}
y={centroidY + pieTextYOffset}
textAnchor="middle"
fontSize={pieTextSize}
> >
{`${getPieDisplayValueFromDatum(arc.data)}`} {({ arcs, path }) => {
</Text> return arcs.map((arc) => {
const [centroidX, centroidY] = path.centroid(arc);
const pathArc = path(arc) as string;
return (
<Group
className={styles.group}
key={`arc-${arc.data.category}`}
>
<path
onMouseMove={(e) => {
const eventSvgCoords = localPoint(
// ownerSVGElement is given by visx docs but not recognized by typescript
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
e.target.ownerSVGElement as Element,
e
) as Point;
showTooltip({
tooltipData: getPieDisplayValueFromDatum(arc.data),
tooltipTop: eventSvgCoords.y,
tooltipLeft: eventSvgCoords.x,
});
}}
onMouseOut={hideTooltip}
className={styles.piePath}
d={pathArc}
/>
<Text
className={styles.pieText}
x={centroidX + pieTextXOffset}
y={centroidY + pieTextYOffset}
textAnchor="middle"
fontSize={pieTextSize}
>
{`${getPieDisplayValueFromDatum(arc.data)}`}
</Text>
</Group>
);
});
}}
</Pie>
<Pie
data={data}
pieValue={(d: PieChartData) => d.value}
innerRadius={pieWidth}
outerRadius={width * 0.5}
>
{(pie) => (
<PieSliceLabel
{...pie}
labelTextSize={labelTextSize}
labelTextXOffset={labelTextXOffset}
labelTextYOffset={labelTextYOffset}
getLabelDisplayValueFromDatum={getLabelDisplayValueFromDatum}
/>
)}
</Pie>
</Group> </Group>
); </svg>
})}
</> {tooltipOpen && (
); <TooltipWrapper
} top={tooltipTop}
left={tooltipLeft}
header={tooltipData as string}
></TooltipWrapper>
)}
</div>
);
}
);
type PieSliceLabelProps<PieChartData> = ProvidedProps<PieChartData> & { type PieSliceLabelProps<PieChartData> = ProvidedProps<PieChartData> & {
labelTextSize: number; labelTextSize: number;