@@ -23,11 +23,6 @@ function SunburstChart({
2323 const clickHandler = useRef ( onClick )
2424 const hoverHandler = useRef ( onHover )
2525
26- /*
27- * I don't think the depthIndex will work, because we're not trying to render a given depth, we're trying to render a folder and all of its children.
28- * So we need to render all children of a given folder at once.
29- */
30-
3126 // this state stores the root node of the sunburst chart
3227 const [ root ] = useState ( ( ) =>
3328 Sentry . startSpan ( { name : 'SunburstChart.createRoot' } , ( ) => {
@@ -41,6 +36,7 @@ function SunburstChart({
4136 while ( stack . length > 0 ) {
4237 const node = stack . pop ( )
4338
39+ // set the value of the node if not previously set
4440 if ( ! ( 'value' in node ) ) {
4541 node . value = selectorHandler . current ( node )
4642 }
@@ -50,32 +46,13 @@ function SunburstChart({
5046 node . children . forEach ( ( child ) => stack . push ( child ) )
5147 }
5248
53- const root = partitionFn ( result ) . each ( ( d ) => ( d . current = d ) )
54-
55- root . each ( ( d ) => {
56- const collection = depthIndex . get ( d . depth ) ?? [ ]
57- collection . push ( d )
58- depthIndex . set ( d . depth , collection )
59- } )
60-
6149 // partition the data and add the `current` property to each node
62- return { root , depthIndex }
50+ return partitionFn ( result ) . each ( ( d ) => ( d . current = d ) )
6351 }
64-
65- // if the node has children, process them
66- if ( Array . isArray ( node . children ) ) {
67- node . children . forEach ( ( child ) => stack . push ( child ) )
68- }
69-
70- const root = partitionFn ( result ) . each ( ( d ) => ( d . current = d ) )
71-
72- // partition the data and add the `current` property to each node
73- return root
7452 } )
7553 )
7654
7755 const [ selectedNode , setSelectedNode ] = useState ( root )
78- const [ forceUpdate , setForceUpdate ] = useState ( false )
7956
8057 // In this case D3 is handling rendering not React, so useLayoutEffect is used to handle rendering
8158 // and changes outside of the React lifecycle.
@@ -121,17 +98,16 @@ function SunburstChart({
12198 . attr ( 'transform' , `translate(${ width / 2 } ,${ width / 2 } )` )
12299
123100 function renderArcs ( ) {
101+ const nodesToRender = selectedNode
102+ . descendants ( )
103+ . slice ( 1 )
104+ . filter ( ( d ) => d . depth <= selectedNode . depth + 2 )
105+
124106 // Renders an arc per data point in the correct location. (Pieces of the circle that add up to a circular graph)
125- console . debug ( 'renderArcs' , selectedNode )
126107 const path = g
127108 . append ( 'g' )
128109 . selectAll ( 'path' )
129- . data (
130- selectedNode
131- . descendants ( )
132- . slice ( 1 )
133- . filter ( ( d ) => d . depth <= selectedNode . depth + 2 )
134- )
110+ . data ( nodesToRender )
135111 . join ( 'path' )
136112 . attr ( 'fill' , ( d ) => color ( d ?. data ?. value || 0 ) )
137113 // If data point is a file fade the background color a bit.
@@ -144,15 +120,25 @@ function SunburstChart({
144120 . filter ( ( d ) => d . children )
145121 . style ( 'cursor' , 'pointer' )
146122 . on ( 'click' , clickedFolder )
147- . on ( 'mouseover' , hoveredFolder )
148- . on ( 'mouseout' , mouseout )
123+ . on ( 'mouseover' , function ( _event , p ) {
124+ select ( this ) . attr ( 'fill-opacity' , 0.6 )
125+ reactHoverCallback ( { target : p , type : 'folder' } )
126+ } )
127+ . on ( 'mouseout' , function ( _event , _node ) {
128+ select ( this ) . attr ( 'fill-opacity' , 1 )
129+ } )
149130
150131 // Events for file
151132 path
152133 . filter ( ( d ) => ! d . children )
153134 . style ( 'cursor' , 'pointer' )
154- . on ( 'click' , clickedFile )
155- . on ( 'mouseover' , hoveredFile )
135+ . on ( 'click' , function ( _event , node ) {
136+ reactClickCallback ( { target : node , type : 'file' } )
137+ } )
138+ . on ( 'mouseover' , function ( _event , node ) {
139+ select ( this ) . attr ( 'fill-opacity' , 0.6 )
140+ reactHoverCallback ( { target : node , type : 'file' } )
141+ } )
156142
157143 // Create a11y label / mouse hover tooltip
158144 const formatTitle = ( d ) => {
@@ -172,54 +158,35 @@ function SunburstChart({
172158 g . append ( 'circle' )
173159 . datum ( selectedNode . parent )
174160 . attr ( 'r' , radius )
161+ . attr ( 'class' , 'fill-none' )
175162 . attr ( 'fill' , 'none' )
176163 . attr ( 'pointer-events' , 'all' )
177- . attr ( 'cursor' , 'pointer' )
164+ . attr ( 'cursor' , ( d ) => ( d ? 'pointer' : 'default' ) )
178165 . on ( 'click' , clickedFolder )
179166 . on ( 'mouseover' , hoveredRoot )
180167
181168 g . append ( 'text' )
182169 . datum ( selectedNode . parent )
183170 . text ( '..' )
184- . attr ( 'fill-opacity' , ( d ) => {
185- // if the parent exists, show the text
186- return d ? 1 : 0
187- } )
171+ // if the parent exists (i.e. not root), show the text
172+ . attr ( 'fill-opacity' , ( d ) => ( d ? 1 : 0 ) )
188173 . attr ( 'text-anchor' , 'middle' )
189- . attr ( 'class' , 'text-7xl fill-ds-gray-quinary' )
174+ . attr ( 'class' , 'text-7xl fill-ds-gray-quinary select-none ' )
190175 . attr ( 'cursor' , 'pointer' )
191176 . on ( 'click' , clickedFolder )
192177 . on ( 'mouseover' , hoveredRoot )
193178
194- function clickedFolder ( _event , p ) {
195- reactClickCallback ( { target : p , type : 'folder' } )
196- changeLocation ( p )
197- }
198-
199- function clickedFile ( _event , p ) {
200- reactClickCallback ( { target : p , type : 'file' } )
179+ function clickedFolder ( _event , node ) {
180+ reactClickCallback ( { target : node , type : 'folder' } )
181+ changeLocation ( node )
201182 }
202183
203- function hoveredRoot ( _event , p ) {
184+ function hoveredRoot ( _event , node ) {
204185 if ( previous ) {
205186 reactHoverCallback ( { target : previous , type : 'folder' } )
206187 return
207188 }
208- reactHoverCallback ( { target : p , type : 'folder' } )
209- }
210-
211- function hoveredFolder ( _event , p ) {
212- select ( this ) . attr ( 'fill-opacity' , 0.6 )
213- reactHoverCallback ( { target : p , type : 'folder' } )
214- }
215-
216- function hoveredFile ( _event , p ) {
217- select ( this ) . attr ( 'fill-opacity' , 0.6 )
218- reactHoverCallback ( { target : p , type : 'file' } )
219- }
220-
221- function mouseout ( _event , _p ) {
222- select ( this ) . attr ( 'fill-opacity' , 1 )
189+ reactHoverCallback ( { target : node , type : 'folder' } )
223190 }
224191
225192 function reactClickCallback ( { target, type } ) {
@@ -264,99 +231,39 @@ function SunburstChart({
264231 }
265232 }
266233
267- function changeLocation ( p ) {
234+ function changeLocation ( node ) {
268235 // Because you can move two layers at a time previous !== parent
269- previous = p
270- // const selected = p.parent || root
271- // const t = transition(g).duration(750)
236+ previous = node
272237
273- if ( p ) {
238+ if ( node ) {
274239 // Update the selected node
275240 setSelectedNode (
276- p . each ( ( d ) => {
241+ node . each ( ( d ) => {
277242 // determine x0 and y0
278- const x0Min = Math . min ( 1 , ( d . x0 - p . x0 ) / ( p . x1 - p . x0 ) )
243+ const x0Min = Math . min ( 1 , ( d . x0 - node . x0 ) / ( node . x1 - node . x0 ) )
279244 const x0 = Math . max ( 0 , x0Min ) * 2 * Math . PI
280- const y0 = Math . max ( 0 , d . y0 - p . depth )
245+ const y0 = Math . max ( 0 , d . y0 - node . depth )
281246
282247 // determine x1 and y1
283- const x1Min = Math . min ( 1 , ( d . x1 - p . x0 ) / ( p . x1 - p . x0 ) )
248+ const x1Min = Math . min ( 1 , ( d . x1 - node . x0 ) / ( node . x1 - node . x0 ) )
284249 const x1 = Math . max ( 0 , x1Min ) * 2 * Math . PI
285- const y1 = Math . max ( 0 , d . y1 - p . depth )
250+ const y1 = Math . max ( 0 , d . y1 - node . depth )
286251
252+ // update the cords for the node
287253 d . current = { x0, y0, x1, y1 }
288254 } )
289255 )
290- setForceUpdate ( ! forceUpdate )
291256 }
292-
293- // handleTextUpdate({ current: p, selected, transition: t })
294257 }
295-
296- // function handleArcsUpdate({ current, selected, transition }) {
297- // parent.datum(selected)
298-
299- // // Handle animating in/out of a folder
300- // root.each((d) => {
301- // // determine x0 and y0
302- // const x0Min = Math.min(
303- // 1,
304- // (d.x0 - current.x0) / (current.x1 - current.x0)
305- // )
306- // const x0 = Math.max(0, x0Min) * 2 * Math.PI
307- // const y0 = Math.max(0, d.y0 - current.depth)
308-
309- // // determine x1 and y1
310- // const x1Min = Math.min(
311- // 1,
312- // (d.x1 - current.x0) / (current.x1 - current.x0)
313- // )
314- // const x1 = Math.max(0, x1Min) * 2 * Math.PI
315- // const y1 = Math.max(0, d.y1 - current.depth)
316-
317- // d.target = { x0, y0, x1, y1 }
318- // })
319-
320- // // Transition the data on all arcs, even the ones that aren’t visible,
321- // // so that if this transition is interrupted, entering arcs will start
322- // // the next transition from the desired position.
323- // path
324- // .transition(transition)
325- // .tween('data', (d) => {
326- // const i = interpolate(d.current, d.target)
327- // return (t) => (d.current = i(t))
328- // })
329- // .filter(function (d) {
330- // return +this.getAttribute('fill-opacity') || arcVisible(d.target)
331- // })
332- // .attr('fill-opacity', (d) =>
333- // arcVisible(d.target) ? (d.children ? 1 : 0.6) : 0
334- // )
335- // .attr('pointer-events', (d) =>
336- // arcVisible(d.target) ? 'auto' : 'none'
337- // )
338- // .attrTween('d', (d) => () => drawArc(d.current))
339- // }
340-
341- // function handleTextUpdate({ current, selected, transition }) {
342- // backText.datum(selected)
343-
344- // // Only show back if not on root
345- // if (current.parent) {
346- // backText.transition(transition).attr('fill-opacity', 1)
347- // } else {
348- // backText.transition(transition).attr('fill-opacity', 0)
349- // }
350- // }
351258 }
352259
353260 renderArcs ( )
354261
355- // On cleanup remove the root DOM generated by D3
356262 return ( ) => {
263+ // On cleanup remove the root DOM generated by D3
357264 g . remove ( )
358265 }
359- } , [ colorDomainMax , colorDomainMin , forceUpdate , selectedNode , svgRenderSize ] )
266+ } , [ colorDomainMax , colorDomainMin , selectedNode , svgRenderSize ] )
360267
361268 return (
362269 < svg
0 commit comments