7
7
* @flow
8
8
*/
9
9
10
- import type {
11
- Point ,
12
- HorizontalPanAndZoomViewOnChangeCallback ,
13
- } from './view-base' ;
10
+ import type { Point } from './view-base' ;
14
11
import type {
15
12
ReactHoverContextInfo ,
16
13
ReactProfilerData ,
17
14
ReactMeasure ,
15
+ ViewState ,
18
16
} from './types' ;
19
17
20
18
import * as React from 'react' ;
21
19
import {
22
20
Fragment ,
21
+ useContext ,
23
22
useEffect ,
24
23
useLayoutEffect ,
25
24
useRef ,
@@ -54,29 +53,37 @@ import {
54
53
UserTimingMarksView ,
55
54
} from './content-views' ;
56
55
import { COLORS } from './content-views/constants' ;
57
-
56
+ import { clampState , moveStateToRange } from './view-base/utils/scrollState' ;
58
57
import EventTooltip from './EventTooltip' ;
58
+ import { RegistryContext } from 'react-devtools-shared/src/devtools/ContextMenu/Contexts' ;
59
59
import ContextMenu from 'react-devtools-shared/src/devtools/ContextMenu/ContextMenu' ;
60
60
import ContextMenuItem from 'react-devtools-shared/src/devtools/ContextMenu/ContextMenuItem' ;
61
61
import useContextMenu from 'react-devtools-shared/src/devtools/ContextMenu/useContextMenu' ;
62
62
import { getBatchRange } from './utils/getBatchRange' ;
63
+ import { MAX_ZOOM_LEVEL , MIN_ZOOM_LEVEL } from './view-base/constants' ;
63
64
64
65
import styles from './CanvasPage.css' ;
65
66
66
67
const CONTEXT_MENU_ID = 'canvas' ;
67
68
68
69
type Props = { |
69
70
profilerData : ReactProfilerData ,
71
+ viewState : ViewState ,
70
72
| } ;
71
73
72
- function CanvasPage ( { profilerData} : Props ) {
74
+ function CanvasPage ( { profilerData, viewState } : Props ) {
73
75
return (
74
76
< div
75
77
className = { styles . CanvasPage }
76
78
style = { { backgroundColor : COLORS . BACKGROUND } } >
77
79
< AutoSizer >
78
80
{ ( { height, width} : { height : number , width : number } ) => (
79
- < AutoSizedCanvas data = { profilerData } height = { height } width = { width } />
81
+ < AutoSizedCanvas
82
+ data = { profilerData }
83
+ height = { height }
84
+ viewState = { viewState }
85
+ width = { width }
86
+ />
80
87
) }
81
88
</ AutoSizer >
82
89
</ div >
@@ -98,27 +105,43 @@ const copySummary = (data: ReactProfilerData, measure: ReactMeasure) => {
98
105
) ;
99
106
} ;
100
107
101
- // TODO (scheduling profiler) Why is the "zoom" feature so much slower than normal rendering?
102
108
const zoomToBatch = (
103
109
data : ReactProfilerData ,
104
110
measure : ReactMeasure ,
105
- syncedHorizontalPanAndZoomViews : HorizontalPanAndZoomView [ ] ,
111
+ viewState : ViewState ,
112
+ width : number ,
106
113
) => {
107
114
const { batchUID} = measure ;
108
- const [ startTime , stopTime ] = getBatchRange ( batchUID , data ) ;
109
- syncedHorizontalPanAndZoomViews . forEach ( syncedView =>
110
- // Using time as range works because the views' intrinsic content size is based on time.
111
- syncedView . zoomToRange ( startTime , stopTime ) ,
112
- ) ;
115
+ const [ rangeStart , rangeEnd ] = getBatchRange ( batchUID , data ) ;
116
+
117
+ // Convert from time range to ScrollState
118
+ const scrollState = moveStateToRange ( {
119
+ state : viewState . horizontalScrollState ,
120
+ rangeStart,
121
+ rangeEnd,
122
+ contentLength : data . duration ,
123
+
124
+ minContentLength : data . duration * MIN_ZOOM_LEVEL ,
125
+ maxContentLength : data . duration * MAX_ZOOM_LEVEL ,
126
+ containerLength : width ,
127
+ } ) ;
128
+
129
+ viewState . updateHorizontalScrollState ( scrollState ) ;
113
130
} ;
114
131
115
132
type AutoSizedCanvasProps = { |
116
133
data : ReactProfilerData ,
117
134
height : number ,
135
+ viewState : ViewState ,
118
136
width : number ,
119
137
| } ;
120
138
121
- function AutoSizedCanvas ( { data, height, width} : AutoSizedCanvasProps ) {
139
+ function AutoSizedCanvas ( {
140
+ data,
141
+ height,
142
+ viewState,
143
+ width,
144
+ } : AutoSizedCanvasProps ) {
122
145
const canvasRef = useRef < HTMLCanvasElement | null > ( null ) ;
123
146
124
147
const [ isContextMenuShown , setIsContextMenuShown ] = useState < boolean > ( false ) ;
@@ -136,30 +159,31 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
136
159
const componentMeasuresViewRef = useRef ( null ) ;
137
160
const reactMeasuresViewRef = useRef ( null ) ;
138
161
const flamechartViewRef = useRef ( null ) ;
139
- const syncedHorizontalPanAndZoomViewsRef = useRef < HorizontalPanAndZoomView [ ] > (
140
- [ ] ,
141
- ) ;
162
+
163
+ const { hideMenu : hideContextMenu } = useContext ( RegistryContext ) ;
142
164
143
165
useLayoutEffect ( ( ) => {
144
166
const surface = surfaceRef . current ;
145
167
const defaultFrame = { origin : zeroPoint , size : { width, height} } ;
146
168
147
- // Clear synced views
148
- syncedHorizontalPanAndZoomViewsRef . current = [ ] ;
169
+ // Auto hide context menu when panning.
170
+ viewState . onHorizontalScrollStateChange ( scrollState => {
171
+ hideContextMenu ( ) ;
172
+ } ) ;
149
173
150
- const syncAllHorizontalPanAndZoomViewStates : HorizontalPanAndZoomViewOnChangeCallback = (
151
- newState ,
152
- triggeringView ? : HorizontalPanAndZoomView ,
153
- ) => {
154
- syncedHorizontalPanAndZoomViewsRef . current . forEach (
155
- syncedView =>
156
- triggeringView !== syncedView && syncedView . setScrollState ( newState ) ,
157
- ) ;
158
- } ;
174
+ // Initialize horizontal view state
175
+ viewState . updateHorizontalScrollState (
176
+ clampState ( {
177
+ state : viewState . horizontalScrollState ,
178
+ minContentLength : data . duration * MIN_ZOOM_LEVEL ,
179
+ maxContentLength : data . duration * MAX_ZOOM_LEVEL ,
180
+ containerLength : defaultFrame . size . width ,
181
+ } ) ,
182
+ ) ;
159
183
160
184
function createViewHelper (
161
185
view : View ,
162
- resizeLabel : string = '' ,
186
+ label : string ,
163
187
shouldScrollVertically : boolean = false ,
164
188
shouldResizeVertically : boolean = false ,
165
189
) : View {
@@ -169,6 +193,8 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
169
193
surface ,
170
194
defaultFrame ,
171
195
view ,
196
+ viewState ,
197
+ label ,
172
198
) ;
173
199
}
174
200
@@ -177,31 +203,30 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
177
203
defaultFrame ,
178
204
verticalScrollView !== null ? verticalScrollView : view ,
179
205
data . duration ,
180
- syncAllHorizontalPanAndZoomViewStates ,
206
+ viewState ,
181
207
) ;
182
208
183
- syncedHorizontalPanAndZoomViewsRef . current . push ( horizontalPanAndZoomView ) ;
184
-
185
- let viewToReturn = horizontalPanAndZoomView ;
209
+ let resizableView = null ;
186
210
if ( shouldResizeVertically ) {
187
- viewToReturn = new ResizableView (
211
+ resizableView = new ResizableView (
188
212
surface ,
189
213
defaultFrame ,
190
214
horizontalPanAndZoomView ,
215
+ viewState ,
191
216
canvasRef ,
192
- resizeLabel ,
217
+ label ,
193
218
) ;
194
219
}
195
220
196
- return viewToReturn ;
221
+ return resizableView || horizontalPanAndZoomView ;
197
222
}
198
223
199
224
const axisMarkersView = new TimeAxisMarkersView (
200
225
surface ,
201
226
defaultFrame ,
202
227
data . duration ,
203
228
) ;
204
- const axisMarkersViewWrapper = createViewHelper ( axisMarkersView ) ;
229
+ const axisMarkersViewWrapper = createViewHelper ( axisMarkersView , 'time' ) ;
205
230
206
231
let userTimingMarksViewWrapper = null ;
207
232
if ( data . otherUserTimingMarks . length > 0 ) {
@@ -212,7 +237,10 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
212
237
data . duration ,
213
238
) ;
214
239
userTimingMarksViewRef . current = userTimingMarksView ;
215
- userTimingMarksViewWrapper = createViewHelper ( userTimingMarksView ) ;
240
+ userTimingMarksViewWrapper = createViewHelper (
241
+ userTimingMarksView ,
242
+ 'user timing api' ,
243
+ ) ;
216
244
}
217
245
218
246
const nativeEventsView = new NativeEventsView ( surface , defaultFrame , data ) ;
@@ -230,7 +258,10 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
230
258
data ,
231
259
) ;
232
260
schedulingEventsViewRef . current = schedulingEventsView ;
233
- const schedulingEventsViewWrapper = createViewHelper ( schedulingEventsView ) ;
261
+ const schedulingEventsViewWrapper = createViewHelper (
262
+ schedulingEventsView ,
263
+ 'react updates' ,
264
+ ) ;
234
265
235
266
let suspenseEventsViewWrapper = null ;
236
267
if ( data . suspenseEvents . length > 0 ) {
@@ -256,7 +287,7 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
256
287
reactMeasuresViewRef . current = reactMeasuresView ;
257
288
const reactMeasuresViewWrapper = createViewHelper (
258
289
reactMeasuresView ,
259
- 'react' ,
290
+ 'react scheduling ' ,
260
291
true ,
261
292
true ,
262
293
) ;
@@ -269,7 +300,10 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
269
300
data ,
270
301
) ;
271
302
componentMeasuresViewRef . current = componentMeasuresView ;
272
- componentMeasuresViewWrapper = createViewHelper ( componentMeasuresView ) ;
303
+ componentMeasuresViewWrapper = createViewHelper (
304
+ componentMeasuresView ,
305
+ 'react components' ,
306
+ ) ;
273
307
}
274
308
275
309
const flamechartView = new FlamechartView (
@@ -329,7 +363,7 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
329
363
return ;
330
364
}
331
365
332
- // Wheel events should always hide the current toolltip .
366
+ // Wheel events should always hide the current tooltip .
333
367
switch ( interaction . type ) {
334
368
case 'wheel-control' :
335
369
case 'wheel-meta' :
@@ -617,11 +651,7 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
617
651
{ measure !== null && (
618
652
< ContextMenuItem
619
653
onClick = { ( ) =>
620
- zoomToBatch (
621
- contextData . data ,
622
- measure ,
623
- syncedHorizontalPanAndZoomViewsRef . current ,
624
- )
654
+ zoomToBatch ( contextData . data , measure , viewState , width )
625
655
}
626
656
title = "Zoom to batch" >
627
657
Zoom to batch
0 commit comments