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' ;
@@ -55,30 +53,37 @@ import {
55
53
UserTimingMarksView ,
56
54
} from './content-views' ;
57
55
import { COLORS } from './content-views/constants' ;
58
-
56
+ import { clampState , moveStateToRange } from './view-base/utils/scrollState' ;
59
57
import EventTooltip from './EventTooltip' ;
60
58
import { RegistryContext } from 'react-devtools-shared/src/devtools/ContextMenu/Contexts' ;
61
59
import ContextMenu from 'react-devtools-shared/src/devtools/ContextMenu/ContextMenu' ;
62
60
import ContextMenuItem from 'react-devtools-shared/src/devtools/ContextMenu/ContextMenuItem' ;
63
61
import useContextMenu from 'react-devtools-shared/src/devtools/ContextMenu/useContextMenu' ;
64
62
import { getBatchRange } from './utils/getBatchRange' ;
63
+ import { MAX_ZOOM_LEVEL , MIN_ZOOM_LEVEL } from './view-base/constants' ;
65
64
66
65
import styles from './CanvasPage.css' ;
67
66
68
67
const CONTEXT_MENU_ID = 'canvas' ;
69
68
70
69
type Props = { |
71
70
profilerData : ReactProfilerData ,
71
+ viewState : ViewState ,
72
72
| } ;
73
73
74
- function CanvasPage ( { profilerData} : Props ) {
74
+ function CanvasPage ( { profilerData, viewState } : Props ) {
75
75
return (
76
76
< div
77
77
className = { styles . CanvasPage }
78
78
style = { { backgroundColor : COLORS . BACKGROUND } } >
79
79
< AutoSizer >
80
80
{ ( { height, width} : { height : number , width : number } ) => (
81
- < AutoSizedCanvas data = { profilerData } height = { height } width = { width } />
81
+ < AutoSizedCanvas
82
+ data = { profilerData }
83
+ height = { height }
84
+ viewState = { viewState }
85
+ width = { width }
86
+ />
82
87
) }
83
88
</ AutoSizer >
84
89
</ div >
@@ -103,23 +108,40 @@ const copySummary = (data: ReactProfilerData, measure: ReactMeasure) => {
103
108
const zoomToBatch = (
104
109
data : ReactProfilerData ,
105
110
measure : ReactMeasure ,
106
- syncedHorizontalPanAndZoomViews : HorizontalPanAndZoomView [ ] ,
111
+ viewState : ViewState ,
112
+ width : number ,
107
113
) => {
108
114
const { batchUID} = measure ;
109
- const [ startTime , stopTime ] = getBatchRange ( batchUID , data ) ;
110
- syncedHorizontalPanAndZoomViews . forEach ( syncedView =>
111
- // Using time as range works because the views' intrinsic content size is based on time.
112
- syncedView . zoomToRange ( startTime , stopTime ) ,
113
- ) ;
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 ) ;
114
130
} ;
115
131
116
132
type AutoSizedCanvasProps = { |
117
133
data : ReactProfilerData ,
118
134
height : number ,
135
+ viewState : ViewState ,
119
136
width : number ,
120
137
| } ;
121
138
122
- function AutoSizedCanvas ( { data, height, width} : AutoSizedCanvasProps ) {
139
+ function AutoSizedCanvas ( {
140
+ data,
141
+ height,
142
+ viewState,
143
+ width,
144
+ } : AutoSizedCanvasProps ) {
123
145
const canvasRef = useRef < HTMLCanvasElement | null > ( null ) ;
124
146
125
147
const [ isContextMenuShown , setIsContextMenuShown ] = useState < boolean > ( false ) ;
@@ -137,35 +159,31 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
137
159
const componentMeasuresViewRef = useRef ( null ) ;
138
160
const reactMeasuresViewRef = useRef ( null ) ;
139
161
const flamechartViewRef = useRef ( null ) ;
140
- const syncedHorizontalPanAndZoomViewsRef = useRef < HorizontalPanAndZoomView [ ] > (
141
- [ ] ,
142
- ) ;
143
162
144
163
const { hideMenu : hideContextMenu } = useContext ( RegistryContext ) ;
145
164
146
165
useLayoutEffect ( ( ) => {
147
166
const surface = surfaceRef . current ;
148
167
const defaultFrame = { origin : zeroPoint , size : { width, height} } ;
149
168
150
- // Clear synced views
151
- syncedHorizontalPanAndZoomViewsRef . current = [ ] ;
152
-
153
- const syncAllHorizontalPanAndZoomViewStates : HorizontalPanAndZoomViewOnChangeCallback = (
154
- newState ,
155
- triggeringView ? : HorizontalPanAndZoomView ,
156
- ) => {
157
- // Hide context menu when panning.
169
+ // Auto hide context menu when panning.
170
+ viewState . onHorizontalScrollStateChange ( scrollState => {
158
171
hideContextMenu ( ) ;
172
+ } ) ;
159
173
160
- syncedHorizontalPanAndZoomViewsRef . current . forEach (
161
- syncedView =>
162
- triggeringView !== syncedView && syncedView . setScrollState ( newState ) ,
163
- ) ;
164
- } ;
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
+ ) ;
165
183
166
184
function createViewHelper (
167
185
view : View ,
168
- resizeLabel : string = '' ,
186
+ label : string ,
169
187
shouldScrollVertically : boolean = false ,
170
188
shouldResizeVertically : boolean = false ,
171
189
) : View {
@@ -175,6 +193,8 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
175
193
surface ,
176
194
defaultFrame ,
177
195
view ,
196
+ viewState ,
197
+ label ,
178
198
) ;
179
199
}
180
200
@@ -183,31 +203,30 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
183
203
defaultFrame ,
184
204
verticalScrollView !== null ? verticalScrollView : view ,
185
205
data . duration ,
186
- syncAllHorizontalPanAndZoomViewStates ,
206
+ viewState ,
187
207
) ;
188
208
189
- syncedHorizontalPanAndZoomViewsRef . current . push ( horizontalPanAndZoomView ) ;
190
-
191
- let viewToReturn = horizontalPanAndZoomView ;
209
+ let resizableView = null ;
192
210
if ( shouldResizeVertically ) {
193
- viewToReturn = new ResizableView (
211
+ resizableView = new ResizableView (
194
212
surface ,
195
213
defaultFrame ,
196
214
horizontalPanAndZoomView ,
215
+ viewState ,
197
216
canvasRef ,
198
- resizeLabel ,
217
+ label ,
199
218
) ;
200
219
}
201
220
202
- return viewToReturn ;
221
+ return resizableView || horizontalPanAndZoomView ;
203
222
}
204
223
205
224
const axisMarkersView = new TimeAxisMarkersView (
206
225
surface ,
207
226
defaultFrame ,
208
227
data . duration ,
209
228
) ;
210
- const axisMarkersViewWrapper = createViewHelper ( axisMarkersView ) ;
229
+ const axisMarkersViewWrapper = createViewHelper ( axisMarkersView , 'time' ) ;
211
230
212
231
let userTimingMarksViewWrapper = null ;
213
232
if ( data . otherUserTimingMarks . length > 0 ) {
@@ -218,7 +237,10 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
218
237
data . duration ,
219
238
) ;
220
239
userTimingMarksViewRef . current = userTimingMarksView ;
221
- userTimingMarksViewWrapper = createViewHelper ( userTimingMarksView ) ;
240
+ userTimingMarksViewWrapper = createViewHelper (
241
+ userTimingMarksView ,
242
+ 'user timing api' ,
243
+ ) ;
222
244
}
223
245
224
246
const nativeEventsView = new NativeEventsView ( surface , defaultFrame , data ) ;
@@ -236,7 +258,10 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
236
258
data ,
237
259
) ;
238
260
schedulingEventsViewRef . current = schedulingEventsView ;
239
- const schedulingEventsViewWrapper = createViewHelper ( schedulingEventsView ) ;
261
+ const schedulingEventsViewWrapper = createViewHelper (
262
+ schedulingEventsView ,
263
+ 'react updates' ,
264
+ ) ;
240
265
241
266
let suspenseEventsViewWrapper = null ;
242
267
if ( data . suspenseEvents . length > 0 ) {
@@ -262,7 +287,7 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
262
287
reactMeasuresViewRef . current = reactMeasuresView ;
263
288
const reactMeasuresViewWrapper = createViewHelper (
264
289
reactMeasuresView ,
265
- 'react' ,
290
+ 'react scheduling ' ,
266
291
true ,
267
292
true ,
268
293
) ;
@@ -275,7 +300,10 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
275
300
data ,
276
301
) ;
277
302
componentMeasuresViewRef . current = componentMeasuresView ;
278
- componentMeasuresViewWrapper = createViewHelper ( componentMeasuresView ) ;
303
+ componentMeasuresViewWrapper = createViewHelper (
304
+ componentMeasuresView ,
305
+ 'react components' ,
306
+ ) ;
279
307
}
280
308
281
309
const flamechartView = new FlamechartView (
@@ -335,7 +363,7 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
335
363
return ;
336
364
}
337
365
338
- // Wheel events should always hide the current toolltip .
366
+ // Wheel events should always hide the current tooltip .
339
367
switch ( interaction . type ) {
340
368
case 'wheel-control' :
341
369
case 'wheel-meta' :
@@ -623,11 +651,7 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
623
651
{ measure !== null && (
624
652
< ContextMenuItem
625
653
onClick = { ( ) =>
626
- zoomToBatch (
627
- contextData . data ,
628
- measure ,
629
- syncedHorizontalPanAndZoomViewsRef . current ,
630
- )
654
+ zoomToBatch ( contextData . data , measure , viewState , width )
631
655
}
632
656
title = "Zoom to batch" >
633
657
Zoom to batch
0 commit comments