Skip to content

Commit

Permalink
feat(sunburst): add innerRadius and renderRootNode props
Browse files Browse the repository at this point in the history
  • Loading branch information
0x706b committed Jan 13, 2023
1 parent 3e639a2 commit f4e76b7
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 6 deletions.
7 changes: 6 additions & 1 deletion packages/arcs/src/centers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ export const useArcCentersTransition = <Datum extends DatumWithArc, ExtraProps =
mode: ArcTransitionMode = 'innerRadius',
extra?: TransitionExtra<Datum, ExtraProps>
) => {
// center root node label
const dataWithCenteredRoot = data.map(d =>
d.arc.innerRadius === 0 ? { ...d, arc: { ...d.arc, outerRadius: 0 } } : d
)

const { animate, config: springConfig } = useMotionConfig()

const phases = useArcTransitionMode<Datum, ExtraProps>(mode, extra)
Expand All @@ -60,7 +65,7 @@ export const useArcCentersTransition = <Datum extends DatumWithArc, ExtraProps =
innerRadius: number
outerRadius: number
} & ExtraProps
>(data, {
>(dataWithCenteredRoot, {
keys: datum => datum.id,
initial: phases.update,
from: phases.enter,
Expand Down
4 changes: 3 additions & 1 deletion packages/sunburst/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@
"@nivo/colors": "0.80.0",
"@nivo/tooltip": "0.80.0",
"d3-hierarchy": "^1.1.8",
"d3-scale": "^3.2.3",
"lodash": "^4.17.21"
},
"devDependencies": {
"@nivo/core": "0.80.0",
"@types/d3-hierarchy": "^1.1.7"
"@types/d3-hierarchy": "^1.1.7",
"d3-scale": "^3.2.3"
},
"peerDependencies": {
"@nivo/core": "0.80.0",
Expand Down
4 changes: 4 additions & 0 deletions packages/sunburst/src/Sunburst.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ const InnerSunburst = <RawDatum,>({
data,
id = defaultProps.id,
value = defaultProps.value,
innerRadius = defaultProps.innerRadius,
renderRootNode = defaultProps.renderRootNode,
valueFormat,
cornerRadius = defaultProps.cornerRadius,
layers = defaultProps.layers as SunburstLayer<RawDatum>[],
Expand Down Expand Up @@ -73,6 +75,8 @@ const InnerSunburst = <RawDatum,>({
valueFormat,
radius,
cornerRadius,
innerRadius,
renderRootNode,
colors,
colorBy,
inheritColorFromParent,
Expand Down
25 changes: 22 additions & 3 deletions packages/sunburst/src/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useMemo } from 'react'
import { partition as d3Partition, hierarchy as d3Hierarchy } from 'd3-hierarchy'
import { scaleRadial as d3ScaleRadial } from 'd3-scale'
import cloneDeep from 'lodash/cloneDeep'
import sortBy from 'lodash/sortBy'
import { usePropertyAccessor, useTheme, useValueFormatter } from '@nivo/core'
Expand All @@ -21,6 +22,8 @@ export const useSunburst = <RawDatum>({
valueFormat,
radius,
cornerRadius = defaultProps.cornerRadius,
innerRadius = defaultProps.innerRadius,
renderRootNode = defaultProps.renderRootNode,
colors = defaultProps.colors,
colorBy = defaultProps.colorBy,
inheritColorFromParent = defaultProps.inheritColorFromParent,
Expand All @@ -32,6 +35,8 @@ export const useSunburst = <RawDatum>({
valueFormat?: DataProps<RawDatum>['valueFormat']
radius: number
cornerRadius?: SunburstCommonProps<RawDatum>['cornerRadius']
innerRadius?: SunburstCommonProps<RawDatum>['innerRadius']
renderRootNode?: SunburstCommonProps<RawDatum>['renderRootNode']
colors?: SunburstCommonProps<RawDatum>['colors']
colorBy?: SunburstCommonProps<RawDatum>['colorBy']
inheritColorFromParent?: SunburstCommonProps<RawDatum>['inheritColorFromParent']
Expand All @@ -58,7 +63,9 @@ export const useSunburst = <RawDatum>({

const partition = d3Partition<RawDatum>().size([2 * Math.PI, radius * radius])
// exclude root node
const descendants = partition(hierarchy).descendants().slice(1)
const descendants = renderRootNode
? partition(hierarchy).descendants()
: partition(hierarchy).descendants().slice(1)

const total = hierarchy.value ?? 0

Expand All @@ -68,6 +75,12 @@ export const useSunburst = <RawDatum>({
// are going to be computed first
const sortedNodes = sortBy(descendants, 'depth')

const innerRadiusOffset = radius * Math.min(innerRadius, 1)

const maxDepth = Math.max(...sortedNodes.map(n => n.depth))

const scale = d3ScaleRadial().domain([0, maxDepth]).range([innerRadiusOffset, radius])

return sortedNodes.reduce<ComputedDatum<RawDatum>[]>((acc, descendant) => {
const id = getId(descendant.data)
// d3 hierarchy node value is optional by default as it depends on
Expand All @@ -82,8 +95,12 @@ export const useSunburst = <RawDatum>({
const arc: Arc = {
startAngle: descendant.x0,
endAngle: descendant.x1,
innerRadius: Math.sqrt(descendant.y0),
outerRadius: Math.sqrt(descendant.y1),
innerRadius:
renderRootNode && descendant.depth === 0 ? 0 : scale(descendant.depth - 1),
outerRadius:
renderRootNode && descendant.depth === 0
? innerRadius
: scale(descendant.depth),
}

let parent: ComputedDatum<RawDatum> | undefined
Expand Down Expand Up @@ -125,6 +142,8 @@ export const useSunburst = <RawDatum>({
getColor,
inheritColorFromParent,
getChildColor,
innerRadius,
renderRootNode,
])

const arcGenerator = useArcGenerator({ cornerRadius })
Expand Down
2 changes: 2 additions & 0 deletions packages/sunburst/src/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export const defaultProps = {
id: 'id',
value: 'value',
cornerRadius: 0,
innerRadius: 0.4,
renderRootNode: false,
layers: ['arcs', 'arcLabels'] as SunburstLayerId[],
colors: { scheme: 'nivo' } as unknown as OrdinalColorScaleConfig,
colorBy: 'id' as const,
Expand Down
2 changes: 2 additions & 0 deletions packages/sunburst/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ export type SunburstCommonProps<RawDatum> = {
height: number
margin?: Box
cornerRadius: number
innerRadius: number
renderRootNode: boolean
theme: Theme
colors: OrdinalColorScaleConfig<Omit<ComputedDatum<RawDatum>, 'color' | 'fill'>>
colorBy: 'id' | 'depth'
Expand Down
15 changes: 14 additions & 1 deletion packages/sunburst/stories/sunburst.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useState } from 'react'
import { storiesOf } from '@storybook/react'
import { action } from '@storybook/addon-actions'
import { withKnobs, boolean, select } from '@storybook/addon-knobs'
import { withKnobs, boolean, select, number } from '@storybook/addon-knobs'
// @ts-ignore
import { linearGradientDef, patternDotsDef, useTheme } from '@nivo/core'
// @ts-ignore
Expand Down Expand Up @@ -223,3 +223,16 @@ const CenteredMetric = ({ nodes, centerX, centerY }: SunburstCustomLayerProps<Ra
stories.add('adding a metric in the center using a custom layer', () => (
<Sunburst<RawDatum> {...commonProperties} layers={['arcs', 'arcLabels', CenteredMetric]} />
))

stories.add('with root node', () => (
<Sunburst<RawDatum>
{...commonProperties}
innerRadius={number('innerRadius', 0.25, {
range: true,
min: 0.0,
max: 0.95,
step: 0.05,
})}
renderRootNode={boolean('renderRootNode', true)}
/>
))
23 changes: 23 additions & 0 deletions website/src/data/components/sunburst/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,29 @@ const props: ChartProperty[] = [
step: 1,
},
},
{
key: 'innerRadius',
help: `Size of the center circle. Value should be between 0~1 as it's a ratio from original radius.`,
type: 'number',
required: false,
defaultValue: defaultProps.innerRadiusRatio,
group: 'Base',
control: {
type: 'range',
min: 0,
max: 0.95,
step: 0.05
},
},
{
key: 'renderRootNode',
help: `Render the root node. By default, the root node is omitted.`,
type: 'boolean',
required: false,
defaultValue: defaultProps.renderRootNode,
control: { type: 'switch' },
group: 'Base',
},
...chartDimensions(allFlavors),
themeProperty(['svg', 'api']),
ordinalColors({
Expand Down
2 changes: 2 additions & 0 deletions website/src/pages/sunburst/api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ const SunburstApi = () => {
value: 'loc',
valueFormat: { format: '', enabled: false },
cornerRadius: 2,
innerRadius: 0.4,
renderRootNode: false,
borderWidth: 1,
borderColor: 'white',
colors: { scheme: 'nivo' },
Expand Down
2 changes: 2 additions & 0 deletions website/src/pages/sunburst/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ const initialProperties = {
value: 'loc',
valueFormat: { format: '', enabled: false },
cornerRadius: 2,
innerRadius: 0.4,
renderRootNode: false,
borderWidth: 1,
borderColor: { theme: 'background' },
colors: { scheme: 'nivo' },
Expand Down

0 comments on commit f4e76b7

Please sign in to comment.