Skip to content

Commit 38f6979

Browse files
committed
fix:
1 parent 3a9d866 commit 38f6979

File tree

11 files changed

+26026
-34357
lines changed

11 files changed

+26026
-34357
lines changed

packages/sunburst/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
"@nivo/core": "workspace:*",
3535
"@nivo/tooltip": "workspace:*",
3636
"@types/d3-hierarchy": "^1.1.8",
37+
"@types/d3-scale": "^4.0.8",
3738
"d3-hierarchy": "^1.1.8",
39+
"d3-scale": "^4.0.2",
3840
"lodash": "^4.17.21"
3941
},
4042
"peerDependencies": {

packages/sunburst/src/Sunburst.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ const InnerSunburst = <RawDatum,>({
2525
data,
2626
id = defaultProps.id,
2727
value = defaultProps.value,
28+
innerRadius = defaultProps.innerRadius,
29+
renderRootNode = defaultProps.renderRootNode,
2830
valueFormat,
2931
cornerRadius = defaultProps.cornerRadius,
3032
layers = defaultProps.layers as SunburstLayer<RawDatum>[],
@@ -73,6 +75,8 @@ const InnerSunburst = <RawDatum,>({
7375
valueFormat,
7476
radius,
7577
cornerRadius,
78+
innerRadius,
79+
renderRootNode,
7680
colors,
7781
colorBy,
7882
inheritColorFromParent,

packages/sunburst/src/hooks.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useMemo } from 'react'
22
import { partition as d3Partition, hierarchy as d3Hierarchy } from 'd3-hierarchy'
3+
import { scaleRadial as d3ScaleRadial } from 'd3-scale'
34
import cloneDeep from 'lodash/cloneDeep'
45
import sortBy from 'lodash/sortBy'
56
import { usePropertyAccessor, useTheme, useValueFormatter } from '@nivo/core'
@@ -21,6 +22,8 @@ export const useSunburst = <RawDatum>({
2122
valueFormat,
2223
radius,
2324
cornerRadius = defaultProps.cornerRadius,
25+
innerRadius = defaultProps.innerRadius,
26+
renderRootNode = defaultProps.renderRootNode,
2427
colors = defaultProps.colors,
2528
colorBy = defaultProps.colorBy,
2629
inheritColorFromParent = defaultProps.inheritColorFromParent,
@@ -32,6 +35,8 @@ export const useSunburst = <RawDatum>({
3235
valueFormat?: DataProps<RawDatum>['valueFormat']
3336
radius: number
3437
cornerRadius?: SunburstCommonProps<RawDatum>['cornerRadius']
38+
innerRadius?: SunburstCommonProps<RawDatum>['innerRadius']
39+
renderRootNode?: SunburstCommonProps<RawDatum>['renderRootNode']
3540
colors?: SunburstCommonProps<RawDatum>['colors']
3641
colorBy?: SunburstCommonProps<RawDatum>['colorBy']
3742
inheritColorFromParent?: SunburstCommonProps<RawDatum>['inheritColorFromParent']
@@ -57,8 +62,10 @@ export const useSunburst = <RawDatum>({
5762
const hierarchy = d3Hierarchy(clonedData).sum(getValue)
5863

5964
const partition = d3Partition<RawDatum>().size([2 * Math.PI, radius * radius])
60-
// exclude root node
61-
const descendants = partition(hierarchy).descendants().slice(1)
65+
// exclude root node if renderRootNode is false
66+
const descendants = renderRootNode
67+
? partition(hierarchy).descendants()
68+
: partition(hierarchy).descendants().slice(1)
6269

6370
const total = hierarchy.value ?? 0
6471

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

78+
const innerRadiusOffset = radius * Math.min(innerRadius, 1)
79+
80+
const maxDepth = Math.max(...sortedNodes.map(n => n.depth))
81+
82+
const radiusScale = d3ScaleRadial().domain([0, maxDepth]).range([innerRadiusOffset, radius])
83+
7184
return sortedNodes.reduce<ComputedDatum<RawDatum>[]>((acc, descendant) => {
7285
const id = getId(descendant.data)
7386
// d3 hierarchy node value is optional by default as it depends on
@@ -78,12 +91,13 @@ export const useSunburst = <RawDatum>({
7891
const value = descendant.value!
7992
const percentage = (100 * value) / total
8093
const path = descendant.ancestors().map(ancestor => getId(ancestor.data))
94+
const isRootNode = renderRootNode && descendant.depth === 0
8195

8296
const arc: Arc = {
8397
startAngle: descendant.x0,
8498
endAngle: descendant.x1,
85-
innerRadius: Math.sqrt(descendant.y0),
86-
outerRadius: Math.sqrt(descendant.y1),
99+
innerRadius: isRootNode ? 0 : radiusScale(descendant.depth - 1),
100+
outerRadius: isRootNode ? innerRadiusOffset : radiusScale(descendant.depth),
87101
}
88102

89103
let parent: ComputedDatum<RawDatum> | undefined
@@ -118,6 +132,8 @@ export const useSunburst = <RawDatum>({
118132
}, [
119133
data,
120134
radius,
135+
innerRadius,
136+
renderRootNode,
121137
getValue,
122138
getId,
123139
valueFormat,

packages/sunburst/src/props.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ export const defaultProps = {
77
id: 'id',
88
value: 'value',
99
cornerRadius: 0,
10+
innerRadius: 0.4,
11+
renderRootNode: false,
1012
layers: ['arcs', 'arcLabels'] as SunburstLayerId[],
1113
colors: { scheme: 'nivo' } as unknown as OrdinalColorScaleConfig,
1214
colorBy: 'id' as const,

packages/sunburst/src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ export type SunburstCommonProps<RawDatum> = {
5656
height: number
5757
margin?: Box
5858
cornerRadius: number
59+
innerRadius: number
60+
renderRootNode: boolean
5961
theme: Theme
6062
colors: OrdinalColorScaleConfig<Omit<ComputedDatum<RawDatum>, 'color' | 'fill'>>
6163
colorBy: 'id' | 'depth'

packages/sunburst/tests/Sunburst.test.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,35 @@ describe('Sunburst', () => {
183183
expect(layer.exists()).toBeTruthy()
184184
expect(layer.prop('arcGenerator').cornerRadius()()).toEqual(3)
185185
})
186+
187+
it('should render the root node correctly when innerRadius and renderRootNode are set', () => {
188+
const width = 400
189+
const height = 400
190+
const innerRadiusProp = 0.6
191+
192+
// Assuming default margins { top: 0, right: 0, bottom: 0, left: 0 }
193+
// as per Sunburst defaultProps
194+
const chartRadius = Math.min(width, height) / 2
195+
const expectedRootOuterRadius = chartRadius * innerRadiusProp
196+
197+
const wrapper = mount(
198+
<Sunburst
199+
width={width}
200+
height={height}
201+
data={sampleData} // sampleData has a root with id: 'root'
202+
innerRadius={innerRadiusProp}
203+
renderRootNode
204+
/>
205+
)
206+
207+
const rootArcShape = wrapper.find(ArcShape).filterWhere(n => n.prop('datum').depth === 0)
208+
expect(rootArcShape.exists()).toBe(true)
209+
210+
const rootDatum = rootArcShape.prop('datum')
211+
expect(rootDatum.id).toEqual('root') // Verify we got the correct root node
212+
expect(rootDatum.arc.innerRadius).toEqual(0)
213+
expect(rootDatum.arc.outerRadius).toEqual(expectedRootOuterRadius)
214+
})
186215
})
187216

188217
describe('colors', () => {

0 commit comments

Comments
 (0)