11import { useMemo } from 'react'
22import { partition as d3Partition , hierarchy as d3Hierarchy } from 'd3-hierarchy'
3+ import { scaleRadial as d3ScaleRadial } from 'd3-scale'
34import cloneDeep from 'lodash/cloneDeep.js'
45import sortBy from 'lodash/sortBy.js'
56import { usePropertyAccessor , useValueFormatter } from '@nivo/core'
@@ -22,6 +23,8 @@ export const useSunburst = <RawDatum>({
2223 valueFormat,
2324 radius,
2425 cornerRadius = defaultProps . cornerRadius ,
26+ innerRadius = defaultProps . innerRadius ,
27+ renderRootNode = defaultProps . renderRootNode ,
2528 colors = defaultProps . colors ,
2629 colorBy = defaultProps . colorBy ,
2730 inheritColorFromParent = defaultProps . inheritColorFromParent ,
@@ -33,6 +36,8 @@ export const useSunburst = <RawDatum>({
3336 valueFormat ?: DataProps < RawDatum > [ 'valueFormat' ]
3437 radius : number
3538 cornerRadius ?: SunburstCommonProps < RawDatum > [ 'cornerRadius' ]
39+ innerRadius ?: SunburstCommonProps < RawDatum > [ 'innerRadius' ]
40+ renderRootNode ?: SunburstCommonProps < RawDatum > [ 'renderRootNode' ]
3641 colors ?: SunburstCommonProps < RawDatum > [ 'colors' ]
3742 colorBy ?: SunburstCommonProps < RawDatum > [ 'colorBy' ]
3843 inheritColorFromParent ?: SunburstCommonProps < RawDatum > [ 'inheritColorFromParent' ]
@@ -58,8 +63,10 @@ export const useSunburst = <RawDatum>({
5863 const hierarchy = d3Hierarchy ( clonedData ) . sum ( getValue )
5964
6065 const partition = d3Partition < RawDatum > ( ) . size ( [ 2 * Math . PI , radius * radius ] )
61- // exclude root node
62- const descendants = partition ( hierarchy ) . descendants ( ) . slice ( 1 )
66+ // exclude root node if renderRootNode is false
67+ const descendants = renderRootNode
68+ ? partition ( hierarchy ) . descendants ( )
69+ : partition ( hierarchy ) . descendants ( ) . slice ( 1 )
6370
6471 const total = hierarchy . value ?? 0
6572
@@ -69,6 +76,12 @@ export const useSunburst = <RawDatum>({
6976 // are going to be computed first
7077 const sortedNodes = sortBy ( descendants , 'depth' )
7178
79+ const innerRadiusOffset = radius * Math . min ( innerRadius , 1 )
80+
81+ const maxDepth = Math . max ( ...sortedNodes . map ( n => n . depth ) )
82+
83+ const radiusScale = d3ScaleRadial ( ) . domain ( [ 0 , maxDepth ] ) . range ( [ innerRadiusOffset , radius ] )
84+
7285 return sortedNodes . reduce < ComputedDatum < RawDatum > [ ] > ( ( acc , descendant ) => {
7386 const id = getId ( descendant . data )
7487 // d3 hierarchy node value is optional by default as it depends on
@@ -79,12 +92,13 @@ export const useSunburst = <RawDatum>({
7992 const value = descendant . value !
8093 const percentage = ( 100 * value ) / total
8194 const path = descendant . ancestors ( ) . map ( ancestor => getId ( ancestor . data ) )
95+ const isRootNode = renderRootNode && descendant . depth === 0
8296
8397 const arc : Arc = {
8498 startAngle : descendant . x0 ,
8599 endAngle : descendant . x1 ,
86- innerRadius : Math . sqrt ( descendant . y0 ) ,
87- outerRadius : Math . sqrt ( descendant . y1 ) ,
100+ innerRadius : isRootNode ? 0 : radiusScale ( descendant . depth - 1 ) ,
101+ outerRadius : isRootNode ? innerRadiusOffset : radiusScale ( descendant . depth ) ,
88102 }
89103
90104 let parent : ComputedDatum < RawDatum > | undefined
@@ -119,6 +133,8 @@ export const useSunburst = <RawDatum>({
119133 } , [
120134 data ,
121135 radius ,
136+ innerRadius ,
137+ renderRootNode ,
122138 getValue ,
123139 getId ,
124140 valueFormat ,
0 commit comments