@@ -27,38 +27,40 @@ function SunburstChart({
27
27
const hoverHandler = useRef ( onHover )
28
28
29
29
// this state stores the root node of the sunburst chart
30
- const [ root ] = useState ( ( ) => {
31
- // go through the data and add `value` to each node
32
- const stack = [ data ]
33
- const nodeMap = new Map ( )
34
-
35
- // create a new root node with the value of the root node
36
- const result = { ...data , value : selectorHandler . current ( data ) }
37
- // add the root node to the node map
38
- nodeMap . set ( data , result )
39
-
40
- // while there are nodes to process, pop the last node from the stack
41
- while ( stack . length > 0 ) {
42
- const node = stack . pop ( )
43
- const currentNode = nodeMap . get ( node )
44
-
45
- // if the node has children, process them
46
- if ( Array . isArray ( node . children ) ) {
47
- currentNode . children = node . children . map ( ( child ) => {
48
- // sad ... some browsers still lack support for structuredClone
49
- const newChild = JSON . parse ( JSON . stringify ( child ) )
50
- Object . assign ( newChild , { value : selectorHandler . current ( child ) } )
51
-
52
- nodeMap . set ( child , newChild )
53
- stack . push ( child )
54
- return newChild
55
- } )
30
+ const [ root ] = useState (
31
+ Sentry . startSpan ( { name : 'SunburstChart.createRoot' } , ( ) => {
32
+ // go through the data and add `value` to each node
33
+ const stack = [ data ]
34
+ const nodeMap = new Map ( )
35
+
36
+ // create a new root node with the value of the root node
37
+ const result = { ...data , value : selectorHandler . current ( data ) }
38
+ // add the root node to the node map
39
+ nodeMap . set ( data , result )
40
+
41
+ // while there are nodes to process, pop the last node from the stack
42
+ while ( stack . length > 0 ) {
43
+ const node = stack . pop ( )
44
+ const currentNode = nodeMap . get ( node )
45
+
46
+ // if the node has children, process them
47
+ if ( Array . isArray ( node . children ) ) {
48
+ currentNode . children = node . children . map ( ( child ) => {
49
+ // sad ... some browsers still lack support for structuredClone
50
+ const newChild = JSON . parse ( JSON . stringify ( child ) )
51
+ Object . assign ( newChild , { value : selectorHandler . current ( child ) } )
52
+
53
+ nodeMap . set ( child , newChild )
54
+ stack . push ( child )
55
+ return newChild
56
+ } )
57
+ }
56
58
}
57
- }
58
59
59
- // partition the data and add the `current` property to each node
60
- return partitionFn ( result ) . each ( ( d ) => ( d . current = d ) )
61
- } )
60
+ // partition the data and add the `current` property to each node
61
+ return partitionFn ( result ) . each ( ( d ) => ( d . current = d ) )
62
+ } )
63
+ )
62
64
63
65
// In this case D3 is handling rendering not React, so useLayoutEffect is used to handle rendering
64
66
// and changes outside of the React lifecycle.
@@ -73,20 +75,24 @@ function SunburstChart({
73
75
const radius = width / 6
74
76
75
77
// Creates a function for creating arcs representing files and folders.
76
- const drawArc = arc ( )
77
- . startAngle ( ( d ) => d . x0 )
78
- . endAngle ( ( d ) => d . x1 )
79
- . padAngle ( ( d ) => Math . min ( ( d . x1 - d . x0 ) / 2 , 0.005 ) )
80
- . padRadius ( radius * 1.5 )
81
- . innerRadius ( ( d ) => d . y0 * radius )
82
- . outerRadius ( ( d ) => Math . max ( d . y0 * radius , d . y1 * radius - 1 ) )
78
+ const drawArc = Sentry . startSpan ( { name : 'SunburstChart.drawArc' } , ( ) =>
79
+ arc ( )
80
+ . startAngle ( ( d ) => d . x0 )
81
+ . endAngle ( ( d ) => d . x1 )
82
+ . padAngle ( ( d ) => Math . min ( ( d . x1 - d . x0 ) / 2 , 0.005 ) )
83
+ . padRadius ( radius * 1.5 )
84
+ . innerRadius ( ( d ) => d . y0 * radius )
85
+ . outerRadius ( ( d ) => Math . max ( d . y0 * radius , d . y1 * radius - 1 ) )
86
+ )
83
87
84
88
// A color function you can pass a number from 0-100 to and get a color back from the specified color range
85
89
// Ex color(10.4)
86
- const color = scaleSequential ( )
87
- . domain ( [ colorDomainMin , colorDomainMax ] )
88
- . interpolator ( colorRange )
89
- . clamp ( true )
90
+ const color = Sentry . startSpan ( { name : 'SunburstChart.color' } , ( ) =>
91
+ scaleSequential ( )
92
+ . domain ( [ colorDomainMin , colorDomainMax ] )
93
+ . interpolator ( colorRange )
94
+ . clamp ( true )
95
+ )
90
96
91
97
// Tracks previous location for rendering .. in the breadcrumb.
92
98
let previous
@@ -100,18 +106,22 @@ function SunburstChart({
100
106
. attr ( 'transform' , `translate(${ width / 2 } ,${ width / 2 } )` )
101
107
102
108
// Renders an arc per data point in the correct location. (Pieces of the circle that add up to a circular graph)
103
- const path = g
104
- . append ( 'g' )
105
- . selectAll ( 'path' )
106
- . data ( root . descendants ( ) . slice ( 1 ) )
107
- . join ( 'path' )
108
- . attr ( 'fill' , ( d ) => color ( d ?. data ?. value || 0 ) )
109
- // If data point is a file fade the background color a bit.
110
- . attr ( 'fill-opacity' , ( d ) =>
111
- arcVisible ( d . current ) ? ( d . children ? 1 : 0.6 ) : 0
112
- )
113
- . attr ( 'pointer-events' , ( d ) => ( arcVisible ( d . current ) ? 'auto' : 'none' ) )
114
- . attr ( 'd' , ( d ) => drawArc ( d . current ) )
109
+ const path = Sentry . startSpan ( { name : 'SunburstChart.renderArcs' } , ( ) =>
110
+ g
111
+ . append ( 'g' )
112
+ . selectAll ( 'path' )
113
+ . data ( root . descendants ( ) . slice ( 1 ) )
114
+ . join ( 'path' )
115
+ . attr ( 'fill' , ( d ) => color ( d ?. data ?. value || 0 ) )
116
+ // If data point is a file fade the background color a bit.
117
+ . attr ( 'fill-opacity' , ( d ) =>
118
+ arcVisible ( d . current ) ? ( d . children ? 1 : 0.6 ) : 0
119
+ )
120
+ . attr ( 'pointer-events' , ( d ) =>
121
+ arcVisible ( d . current ) ? 'auto' : 'none'
122
+ )
123
+ . attr ( 'd' , ( d ) => drawArc ( d . current ) )
124
+ )
115
125
116
126
// Events for folders
117
127
path
@@ -233,50 +243,56 @@ function SunburstChart({
233
243
handleTextUpdate ( { current : p , selected, transition : t } )
234
244
}
235
245
236
- function handleArcsUpdate ( { current, selected, transition } ) {
237
- parent . datum ( selected )
238
-
239
- // Handle animating in/out of a folder
240
- root . each ( ( d ) => {
241
- // determine x0 and y0
242
- const x0Min = Math . min (
243
- 1 ,
244
- ( d . x0 - current . x0 ) / ( current . x1 - current . x0 )
246
+ const handleArcsUpdate = ( { current, selected, transition } ) =>
247
+ Sentry . startSpan ( { name : 'SunburstChart.handleArcsUpdate' } , ( ) => {
248
+ parent . datum ( selected )
249
+
250
+ // Handle animating in/out of a folder
251
+ Sentry . startSpan ( { name : 'SunburstChart.calculateCoordinates' } , ( ) =>
252
+ root . each ( ( d ) => {
253
+ // determine x0 and y0
254
+ const x0Min = Math . min (
255
+ 1 ,
256
+ ( d . x0 - current . x0 ) / ( current . x1 - current . x0 )
257
+ )
258
+ const x0 = Math . max ( 0 , x0Min ) * 2 * Math . PI
259
+ const y0 = Math . max ( 0 , d . y0 - current . depth )
260
+
261
+ // determine x1 and y1
262
+ const x1Min = Math . min (
263
+ 1 ,
264
+ ( d . x1 - current . x0 ) / ( current . x1 - current . x0 )
265
+ )
266
+ const x1 = Math . max ( 0 , x1Min ) * 2 * Math . PI
267
+ const y1 = Math . max ( 0 , d . y1 - current . depth )
268
+
269
+ d . target = { x0, y0, x1, y1 }
270
+ } )
245
271
)
246
- const x0 = Math . max ( 0 , x0Min ) * 2 * Math . PI
247
- const y0 = Math . max ( 0 , d . y0 - current . depth )
248
272
249
- // determine x1 and y1
250
- const x1Min = Math . min (
251
- 1 ,
252
- ( d . x1 - current . x0 ) / ( current . x1 - current . x0 )
273
+ // Transition the data on all arcs, even the ones that aren’t visible,
274
+ // so that if this transition is interrupted, entering arcs will start
275
+ // the next transition from the desired position.
276
+ Sentry . startSpan ( { name : 'SunburstChart.transitionArcs' } , ( ) =>
277
+ path
278
+ . transition ( transition )
279
+ . tween ( 'data' , ( d ) => {
280
+ const i = interpolate ( d . current , d . target )
281
+ return ( t ) => ( d . current = i ( t ) )
282
+ } )
283
+ . filter ( function ( d ) {
284
+ return + this . getAttribute ( 'fill-opacity' ) || arcVisible ( d . target )
285
+ } )
286
+ . attr ( 'fill-opacity' , ( d ) =>
287
+ arcVisible ( d . target ) ? ( d . children ? 1 : 0.6 ) : 0
288
+ )
289
+ . attr ( 'pointer-events' , ( d ) =>
290
+ arcVisible ( d . target ) ? 'auto' : 'none'
291
+ )
292
+ . attrTween ( 'd' , ( d ) => ( ) => drawArc ( d . current ) )
253
293
)
254
- const x1 = Math . max ( 0 , x1Min ) * 2 * Math . PI
255
- const y1 = Math . max ( 0 , d . y1 - current . depth )
256
-
257
- d . target = { x0, y0, x1, y1 }
258
294
} )
259
295
260
- // Transition the data on all arcs, even the ones that aren’t visible,
261
- // so that if this transition is interrupted, entering arcs will start
262
- // the next transition from the desired position.
263
- path
264
- . transition ( transition )
265
- . tween ( 'data' , ( d ) => {
266
- const i = interpolate ( d . current , d . target )
267
- return ( t ) => ( d . current = i ( t ) )
268
- } )
269
- . filter ( function ( d ) {
270
- return + this . getAttribute ( 'fill-opacity' ) || arcVisible ( d . target )
271
- } )
272
- . attr ( 'fill-opacity' , ( d ) =>
273
- arcVisible ( d . target ) ? ( d . children ? 1 : 0.6 ) : 0
274
- )
275
- . attr ( 'pointer-events' , ( d ) => ( arcVisible ( d . target ) ? 'auto' : 'none' ) )
276
-
277
- . attrTween ( 'd' , ( d ) => ( ) => drawArc ( d . current ) )
278
- }
279
-
280
296
function handleTextUpdate ( { current, selected, transition } ) {
281
297
backText . datum ( selected )
282
298
0 commit comments