1
+ /* eslint-disable no-use-before-define */
1
2
/* eslint-disable react/no-this-in-sfc */
2
3
/* eslint-disable no-unused-vars */
3
4
/* eslint-disable react/prop-types */
@@ -19,147 +20,117 @@ import React, { useEffect, useState, useRef, useCallback } from 'react';
19
20
import * as d3 from 'd3' ;
20
21
// import { addNewSnapshots } from '../actions/actions';
21
22
22
- // const windowRef = useRef(null);
23
- // const winWidth = null;
24
- // const winHeight = null;
25
23
26
- // useEffect(() => {
27
- // if (windowRef.current) {
28
- // winWidth = windowRef.current.offsetHeight;
29
- // winHeight = windowRef.current.offsetWidth;
30
- // console.log('** SETTING WINDOW SIZES: ', winWidth, winHeight);
31
- // }
32
- // }, [windowRef]);
33
-
34
- const PerfView = ( { snapshots, viewIndex } ) => {
35
- const [ chartData , updateChartData ] = useState ( snapshots [ snapshots . length - 1 ] ) ;
24
+ const PerfView = ( { snapshots, viewIndex, width = 600 , height = 600 } ) => {
25
+ console . log ( '***** constructor *****' ) ;
36
26
const svgRef = useRef ( null ) ;
37
27
38
- // Todo: implement update functions...
39
- const [ curZoom , setZoom ] = useState ( null ) ;
40
- const [ width , setWidth ] = useState ( 600 ) ;
41
- const [ height , setHeight ] = useState ( 600 ) ;
28
+ // Figure out which snapshot index to use
29
+ let indexToDisplay = null ;
30
+ if ( viewIndex < 0 ) indexToDisplay = snapshots . length - 1 ;
31
+ else indexToDisplay = viewIndex ;
42
32
43
- // set up color scaling function
44
- const color = d3 . scaleLinear ( )
33
+ // Set up color scaling function
34
+ const colorScale = d3 . scaleLinear ( )
45
35
. domain ( [ 0 , 7 ] )
46
36
. range ( [ 'hsl(152,80%,80%)' , 'hsl(228,30%,40%)' ] )
47
37
. interpolate ( d3 . interpolateHcl ) ;
48
38
49
- // set up circle-packing layout function
39
+ // Set up circle-packing layout function
50
40
const packFunc = useCallback ( data => {
51
41
return d3 . pack ( )
52
42
. size ( [ width , height ] )
53
43
. padding ( 3 ) ( d3 . hierarchy ( data )
54
- . sum ( d => {
55
- // console.log('in pack func. d=', d);
56
- return d . componentData . actualDuration ;
57
- } )
58
- . sort ( ( a , b ) => {
59
- // console.log('in sort func. a&b=', a, b);
60
- return b . value - a . value ;
61
- } ) ) ;
44
+ . sum ( d => { return d . componentData . actualDuration ; } )
45
+ . sort ( ( a , b ) => { return b . value - a . value ; } ) ) ;
62
46
} , [ width , height ] ) ;
63
47
64
- // first run, or user has made changes in their app; clear old tree and get current chartData
48
+ // If indexToDisplay changes, clear old tree nodes
65
49
useEffect ( ( ) => {
66
- console . log ( 'PerfView -> snapshots' , snapshots ) ;
67
- console . log ( 'Current viewIndex: ' , viewIndex ) ;
68
- for ( let i = 0 ; i < snapshots . length ; i ++ ) {
69
- console . log ( `SNAPSHOT[${ i } ] App actualDuration:` , snapshots [ i ] . children [ 0 ] . componentData . actualDuration ) ;
70
- }
71
-
72
- // clear old tree
50
+ console . log ( '***** useEffect - CLEARING' )
73
51
while ( svgRef . current . hasChildNodes ( ) ) {
74
52
svgRef . current . removeChild ( svgRef . current . lastChild ) ;
75
53
}
76
-
77
- let indexToDisplay = null ;
78
- if ( viewIndex < 0 ) indexToDisplay = snapshots . length - 1 ;
79
- else indexToDisplay = viewIndex ;
80
-
81
- updateChartData ( snapshots [ indexToDisplay ] ) ;
82
- console . log ( `Using snapshots[${ indexToDisplay } ]` ) ;
83
- } , [ svgRef , viewIndex , snapshots , chartData ] ) ;
54
+ } , [ indexToDisplay , svgRef ] ) ;
84
55
85
56
useEffect ( ( ) => {
86
- console . log ( 'PerfView -> chartData' , chartData ) ;
57
+ console . log ( `***** useEffect - MAIN -> snapshots[ ${ indexToDisplay } ]` , snapshots [ indexToDisplay ] ) ;
87
58
88
- // generate tree with our data
89
- const packedRoot = packFunc ( chartData ) ;
90
- // console.log('PerfView -> packedRoot', packedRoot);
59
+ // Generate tree with our data
60
+ const packedRoot = packFunc ( snapshots [ indexToDisplay ] ) ;
91
61
92
- // initial focus points at root of tree
93
- let focus = packedRoot ;
62
+ // Set initial focus root node
63
+ let curFocus = packedRoot ;
64
+
65
+ // View [x, y, r]
94
66
let view ;
95
67
96
- // set up viewBox dimensions and onClick for parent svg
68
+ // Set up viewBox dimensions and onClick for parent svg
97
69
const svg = d3 . select ( svgRef . current )
98
70
. attr ( 'viewBox' , `-${ width / 2 } -${ height / 2 } ${ width } ${ height } ` )
99
- . on ( 'click' , ( ) => zoom ( packedRoot ) ) ;
71
+ . on ( 'click' , ( ) => zoomToNode ( packedRoot ) ) ;
100
72
101
- // connect circles below root to data
73
+ // Connect circles below root to data
102
74
const node = svg . append ( 'g' )
103
75
. selectAll ( 'circle' )
104
76
. data ( packedRoot . descendants ( ) . slice ( 1 ) )
105
77
. enter ( ) . append ( 'circle' )
106
- . attr ( 'fill' , d => ( d . children ? color ( d . depth ) : 'white' ) )
78
+ . attr ( 'fill' , d => ( d . children ? colorScale ( d . depth ) : 'white' ) )
107
79
. attr ( 'pointer-events' , d => ( ! d . children ? 'none' : null ) )
108
80
. on ( 'mouseover' , ( ) => d3 . select ( this ) . attr ( 'stroke' , '#000' ) )
109
81
. on ( 'mouseout' , ( ) => d3 . select ( this ) . attr ( 'stroke' , null ) )
110
- . on ( 'click' , d => focus !== d && ( zoom ( d ) , d3 . event . stopPropagation ( ) ) ) ;
82
+ . on ( 'click' , d => curFocus !== d && ( zoomToNode ( d ) , d3 . event . stopPropagation ( ) ) ) ;
111
83
112
- // console.log('PerfView -> node', node);
113
- // console.log('packedRoot.descendants()', packedRoot.descendants());
114
-
115
- // generate text labels
84
+ // Generate text labels. Set (only) root to visible initially
116
85
const label = svg . append ( 'g' )
117
86
. attr ( 'class' , 'perf-chart-labels' )
118
87
. selectAll ( 'text' )
119
88
. data ( packedRoot . descendants ( ) )
120
89
. enter ( ) . append ( 'text' )
121
90
. style ( 'fill-opacity' , d => ( d . parent === packedRoot ? 1 : 0 ) )
122
91
. style ( 'display' , d => ( d . parent === packedRoot ? 'inline' : 'none' ) )
123
- . text ( d => {
124
- // console.log('generating text label for d: ', d);
125
- return `${ d . data . name } : ${ Number . parseFloat ( d . data . componentData . actualDuration ) . toFixed ( 2 ) } ms` ;
126
- } ) ;
92
+ . text ( d => `${ d . data . name } : \
93
+ ${ Number . parseFloat ( d . data . componentData . actualDuration ) . toFixed ( 2 ) } ms` ) ;
127
94
95
+ // Remove any unused nodes
128
96
label . exit ( ) . remove ( ) ;
129
97
node . exit ( ) . remove ( ) ;
130
98
131
- // jump to default zoom state
132
- zoomTo ( [ packedRoot . x , packedRoot . y , packedRoot . r * 2 ] ) ;
99
+ // Zoom size of nodes and labels to focus view on root node
100
+ zoomViewArea ( [ packedRoot . x , packedRoot . y , packedRoot . r * 2 ] ) ;
133
101
134
- function zoomTo ( v ) {
102
+ // Zoom/relocated nodes and labels based on dimensions given [x, y, r]
103
+ function zoomViewArea ( newXYR ) {
135
104
// console.log("zoomTo -> v", v);
136
- const k = width / v [ 2 ] ;
137
- view = v ;
138
- label . attr ( 'transform' , d => `translate(${ ( d . x - v [ 0 ] ) * k } ,${ ( d . y - v [ 1 ] ) * k } )` ) ;
139
- node . attr ( 'transform' , d => `translate(${ ( d . x - v [ 0 ] ) * k } ,${ ( d . y - v [ 1 ] ) * k } )` ) ;
105
+ const k = width / newXYR [ 2 ] ;
106
+ view = newXYR ;
107
+ label . attr ( 'transform' , d => `translate(${ ( d . x - newXYR [ 0 ] ) * k } ,${ ( d . y - newXYR [ 1 ] ) * k } )` ) ;
108
+ node . attr ( 'transform' , d => `translate(${ ( d . x - newXYR [ 0 ] ) * k } ,${ ( d . y - newXYR [ 1 ] ) * k } )` ) ;
140
109
node . attr ( 'r' , d => d . r * k ) ;
141
110
}
142
111
143
- function zoom ( d ) {
112
+ // Transition visibility of labels
113
+ function zoomToNode ( newFocus ) {
144
114
// console.log("zoom -> d", d);
145
- const focus0 = focus ;
146
- focus = d ;
147
115
148
116
const transition = svg . transition ( )
149
- . duration ( d3 . event . altKey ? 7500 : 750 )
150
- . tween ( 'zoom' , d => {
151
- const i = d3 . interpolateZoom ( view , [ focus . x , focus . y , focus . r * 2 ] ) ;
152
- return t => zoomTo ( i ( t ) ) ;
153
- } ) ;
154
-
155
- label
156
- . filter ( function ( d ) { return d . parent === focus || this . style . display === 'inline' ; } )
117
+ . duration ( d3 . event . altKey ? 7500 : 750 )
118
+ . tween ( 'zoom' , d => {
119
+ const i = d3 . interpolateZoom ( view , [ newFocus . x , newFocus . y , newFocus . r * 2 ] ) ;
120
+ return t => zoomViewArea ( i ( t ) ) ;
121
+ } ) ;
122
+
123
+ // Grab all nodes that were previously displayed, or who's parent is the new target newFocus
124
+ // Transition their labels to visible or not
125
+ label . filter ( function ( d ) { console . log ( 'label filtering. d=' , d ) ; return d . parent === newFocus || this . style . display === 'inline' ; } )
157
126
. transition ( transition )
158
- . style ( 'fill-opacity' , d => ( d . parent === focus ? 1 : 0 ) )
159
- . on ( 'start' , function ( d ) { if ( d . parent === focus ) this . style . display = 'inline' ; } )
160
- . on ( 'end' , function ( d ) { if ( d . parent !== focus ) this . style . display = 'none' ; } ) ;
127
+ . style ( 'fill-opacity' , d => ( d . parent === newFocus ? 1 : 0 ) )
128
+ . on ( 'start' , function ( d ) { if ( d . parent === newFocus ) this . style . display = 'inline' ; } )
129
+ . on ( 'end' , function ( d ) { if ( d . parent !== newFocus ) this . style . display = 'none' ; } ) ;
130
+
131
+ curFocus = newFocus ;
161
132
}
162
- } , [ chartData , color , packFunc , width , height ] ) ;
133
+ } , [ colorScale , packFunc , width , height , indexToDisplay , snapshots ] ) ;
163
134
164
135
return < svg className = "perfContainer" ref = { svgRef } /> ;
165
136
} ;
0 commit comments