From cfc0cb6390c3059fb81d35938ae40387768cde42 Mon Sep 17 00:00:00 2001 From: plouc Date: Sun, 6 Dec 2020 20:27:37 +0900 Subject: [PATCH] feat(pie): add radius offsets support for active arcs --- packages/arcs/README.md | 3 ++ packages/pie/src/Pie.tsx | 4 ++ packages/pie/src/PieCanvas.tsx | 8 +++- packages/pie/src/hooks.ts | 58 +++++++++++++++++++----- packages/pie/src/props.ts | 2 + packages/pie/src/types.ts | 2 + website/src/data/components/pie/props.js | 28 ++++++++++++ website/src/pages/pie/canvas.js | 2 + website/src/pages/pie/index.js | 2 + 9 files changed, 97 insertions(+), 12 deletions(-) diff --git a/packages/arcs/README.md b/packages/arcs/README.md index ab74e75bc..05e24c7fe 100644 --- a/packages/arcs/README.md +++ b/packages/arcs/README.md @@ -1,3 +1,6 @@ # `@nivo/arcs` [![version](https://img.shields.io/npm/v/@nivo/arcs.svg?style=flat-square)](https://www.npmjs.com/package/@nivo/arcs) + +This package is used internally by nivo packages dealing with arcs +such as `@nivo/pie`, `@nivo/chord` and `@nivo/sunburst`. diff --git a/packages/pie/src/Pie.tsx b/packages/pie/src/Pie.tsx index 24aaed21f..a3a6274a5 100644 --- a/packages/pie/src/Pie.tsx +++ b/packages/pie/src/Pie.tsx @@ -31,6 +31,8 @@ const Pie = ({ fit = defaultProps.fit, innerRadius: innerRadiusRatio = defaultProps.innerRadius, cornerRadius = defaultProps.cornerRadius, + activeInnerRadiusOffset = defaultProps.activeInnerRadiusOffset, + activeOuterRadiusOffset = defaultProps.activeOuterRadiusOffset, width, height, @@ -111,6 +113,8 @@ const Pie = ({ padAngle, sortByValue, cornerRadius, + activeInnerRadiusOffset, + activeOuterRadiusOffset, }) const boundDefs = bindDefs(defs, dataWithArc, fill) diff --git a/packages/pie/src/PieCanvas.tsx b/packages/pie/src/PieCanvas.tsx index e2a0476b3..ac9f1c70f 100644 --- a/packages/pie/src/PieCanvas.tsx +++ b/packages/pie/src/PieCanvas.tsx @@ -80,6 +80,8 @@ const PieCanvas = ({ fit = defaultProps.fit, innerRadius: innerRadiusRatio = defaultProps.innerRadius, cornerRadius = defaultProps.cornerRadius, + activeInnerRadiusOffset = defaultProps.activeInnerRadiusOffset, + activeOuterRadiusOffset = defaultProps.activeOuterRadiusOffset, width, height, @@ -136,7 +138,7 @@ const PieCanvas = ({ colors, }) - const { dataWithArc, arcGenerator, centerX, centerY, radius, innerRadius } = usePieFromBox({ + const { dataWithArc, arcGenerator, centerX, centerY, radius, innerRadius, setActiveId } = usePieFromBox({ data: normalizedData, width: innerWidth, height: innerHeight, @@ -147,6 +149,8 @@ const PieCanvas = ({ padAngle, sortByValue, cornerRadius, + activeInnerRadiusOffset, + activeOuterRadiusOffset, }) const getBorderColor = useInheritedColor>(borderColor, theme) @@ -288,8 +292,10 @@ const PieCanvas = ({ const datum = getArcFromMouse(event) if (datum) { onMouseMove?.(datum, event) + setActiveId(datum.id) showTooltipFromEvent(createElement(tooltip, { datum }), event) } else { + setActiveId(null) hideTooltip() } } diff --git a/packages/pie/src/hooks.ts b/packages/pie/src/hooks.ts index 66e0fec49..82f743e18 100644 --- a/packages/pie/src/hooks.ts +++ b/packages/pie/src/hooks.ts @@ -98,13 +98,15 @@ export const useNormalizedData = ({ */ export const usePieArcs = ({ data, - startAngle = defaultProps.startAngle, - endAngle = defaultProps.endAngle, + startAngle, + endAngle, innerRadius, outerRadius, - padAngle = defaultProps.padAngle, - sortByValue = defaultProps.sortByValue, - activeId = null, + padAngle, + sortByValue, + activeId, + activeInnerRadiusOffset, + activeOuterRadiusOffset, }: { data: Omit, 'arc' | 'fill'>[] // in degrees @@ -117,7 +119,9 @@ export const usePieArcs = ({ outerRadius: number padAngle: number sortByValue: boolean - activeId?: null | string | number + activeId: null | string | number + activeInnerRadiusOffset: number + activeOuterRadiusOffset: number }): Omit, 'fill'>[] => { const pie = useMemo(() => { const innerPie = d3Pie, 'arc' | 'fill'>>() @@ -152,8 +156,14 @@ export const usePieArcs = ({ index: arc.index, startAngle: arc.startAngle, endAngle: arc.endAngle, - innerRadius: innerRadius, - outerRadius: activeId === arc.data.id ? outerRadius + 20 : outerRadius, + innerRadius: + activeId === arc.data.id + ? innerRadius - activeInnerRadiusOffset + : innerRadius, + outerRadius: + activeId === arc.data.id + ? outerRadius + activeOuterRadiusOffset + : outerRadius, thickness: outerRadius - innerRadius, padAngle: arc.padAngle, angle, @@ -163,7 +173,15 @@ export const usePieArcs = ({ } ), - [pie, data, innerRadius, outerRadius, activeId] + [ + pie, + data, + innerRadius, + outerRadius, + activeId, + activeInnerRadiusOffset, + activeInnerRadiusOffset, + ] ) } @@ -180,14 +198,23 @@ export const usePie = ({ padAngle = defaultProps.padAngle, sortByValue = defaultProps.sortByValue, cornerRadius = defaultProps.cornerRadius, + activeInnerRadiusOffset = defaultProps.activeInnerRadiusOffset, + activeOuterRadiusOffset = defaultProps.activeOuterRadiusOffset, }: Pick< CompletePieSvgProps, - 'startAngle' | 'endAngle' | 'padAngle' | 'sortByValue' | 'cornerRadius' + | 'startAngle' + | 'endAngle' + | 'padAngle' + | 'sortByValue' + | 'cornerRadius' + | 'activeInnerRadiusOffset' + | 'activeOuterRadiusOffset' > & { data: Omit, 'arc'>[] radius: number innerRadius: number }) => { + const [activeId, setActiveId] = useState(null) const dataWithArc = usePieArcs({ data, startAngle, @@ -196,11 +223,14 @@ export const usePie = ({ outerRadius: radius, padAngle, sortByValue, + activeId, + activeInnerRadiusOffset, + activeOuterRadiusOffset, }) const arcGenerator = useArcGenerator({ cornerRadius }) - return { dataWithArc, arcGenerator } + return { dataWithArc, arcGenerator, setActiveId } } /** @@ -222,6 +252,8 @@ export const usePieFromBox = ({ sortByValue = defaultProps.sortByValue, cornerRadius = defaultProps.cornerRadius, fit = defaultProps.fit, + activeInnerRadiusOffset = defaultProps.activeInnerRadiusOffset, + activeOuterRadiusOffset = defaultProps.activeOuterRadiusOffset, }: Pick< CompletePieSvgProps, | 'width' @@ -233,6 +265,8 @@ export const usePieFromBox = ({ | 'sortByValue' | 'cornerRadius' | 'fit' + | 'activeInnerRadiusOffset' + | 'activeOuterRadiusOffset' > & { data: Omit, 'arc'>[] }) => { @@ -294,6 +328,8 @@ export const usePieFromBox = ({ padAngle, sortByValue, activeId, + activeInnerRadiusOffset, + activeOuterRadiusOffset, }) const arcGenerator = useArcGenerator({ diff --git a/packages/pie/src/props.ts b/packages/pie/src/props.ts index 6bf1b8d68..752ba95ea 100644 --- a/packages/pie/src/props.ts +++ b/packages/pie/src/props.ts @@ -16,6 +16,8 @@ export const defaultProps = { startAngle: 0, endAngle: 360, fit: true, + activeInnerRadiusOffset: 0, + activeOuterRadiusOffset: 0, // border borderWidth: 0, diff --git a/packages/pie/src/types.ts b/packages/pie/src/types.ts index aa99ab84d..0082fbb2d 100644 --- a/packages/pie/src/types.ts +++ b/packages/pie/src/types.ts @@ -86,6 +86,8 @@ export type CommonPieProps = { startAngle: number endAngle: number fit: boolean + activeInnerRadiusOffset: number + activeOuterRadiusOffset: number // colors, theme and border colors: OrdinalColorScaleConfig, 'color' | 'fill' | 'arc'>> diff --git a/website/src/data/components/pie/props.js b/website/src/data/components/pie/props.js index 3ca00e6e0..55f0baef1 100644 --- a/website/src/data/components/pie/props.js +++ b/website/src/data/components/pie/props.js @@ -517,6 +517,34 @@ const props = [ defaultValue: defaultProps.isInteractive, controlType: 'switch', }, + { + key: 'activeInnerRadiusOffset', + help: `Skip label if corresponding slice's angle is lower than provided value.`, + type: 'number', + required: false, + defaultValue: defaultProps.activeInnerRadiusOffset, + controlType: 'range', + group: 'Interactivity', + controlOptions: { + unit: 'px', + min: 0, + max: 50, + }, + }, + { + key: 'activeOuterRadiusOffset', + help: `Skip label if corresponding slice's angle is lower than provided value.`, + type: 'number', + required: false, + defaultValue: defaultProps.activeOuterRadiusOffset, + controlType: 'range', + group: 'Interactivity', + controlOptions: { + unit: 'px', + min: 0, + max: 50, + }, + }, { key: 'onMouseEnter', flavors: ['svg'], diff --git a/website/src/pages/pie/canvas.js b/website/src/pages/pie/canvas.js index f0d1c6c34..36a4b7c3d 100644 --- a/website/src/pages/pie/canvas.js +++ b/website/src/pages/pie/canvas.js @@ -41,6 +41,8 @@ const initialProperties = { padAngle: 0.7, cornerRadius: 3, fit: true, + activeInnerRadiusOffset: defaultProps.activeInnerRadiusOffset, + activeOuterRadiusOffset: 16, colors: { scheme: 'paired' }, diff --git a/website/src/pages/pie/index.js b/website/src/pages/pie/index.js index 4afa014a5..70082fd9a 100644 --- a/website/src/pages/pie/index.js +++ b/website/src/pages/pie/index.js @@ -30,6 +30,8 @@ const initialProperties = { padAngle: 0.7, cornerRadius: 3, fit: defaultProps.fit, + activeInnerRadiusOffset: defaultProps.activeInnerRadiusOffset, + activeOuterRadiusOffset: 16, colors: defaultProps.colors,