77 * @flow
88 */
99
10- import type {
11- Point ,
12- HorizontalPanAndZoomViewOnChangeCallback ,
13- } from './view-base' ;
10+ import type { Point } from './view-base' ;
1411import type {
1512 ReactHoverContextInfo ,
1613 ReactProfilerData ,
1714 ReactMeasure ,
15+ ViewState ,
1816} from './types' ;
1917
2018import * as React from 'react' ;
@@ -55,30 +53,37 @@ import {
5553 UserTimingMarksView ,
5654} from './content-views' ;
5755import { COLORS } from './content-views/constants' ;
58-
56+ import { clampState } from './view-base/utils/scrollState' ;
5957import EventTooltip from './EventTooltip' ;
6058import { RegistryContext } from 'react-devtools-shared/src/devtools/ContextMenu/Contexts' ;
6159import ContextMenu from 'react-devtools-shared/src/devtools/ContextMenu/ContextMenu' ;
6260import ContextMenuItem from 'react-devtools-shared/src/devtools/ContextMenu/ContextMenuItem' ;
6361import useContextMenu from 'react-devtools-shared/src/devtools/ContextMenu/useContextMenu' ;
6462import { getBatchRange } from './utils/getBatchRange' ;
63+ import { MAX_ZOOM_LEVEL , MIN_ZOOM_LEVEL } from './view-base/constants' ;
6564
6665import styles from './CanvasPage.css' ;
6766
6867const CONTEXT_MENU_ID = 'canvas' ;
6968
7069type Props = { |
7170 profilerData : ReactProfilerData ,
71+ viewState : ViewState ,
7272| } ;
7373
74- function CanvasPage ( { profilerData} : Props ) {
74+ function CanvasPage ( { profilerData, viewState } : Props ) {
7575 return (
7676 < div
7777 className = { styles . CanvasPage }
7878 style = { { backgroundColor : COLORS . BACKGROUND } } >
7979 < AutoSizer >
8080 { ( { 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+ />
8287 ) }
8388 </ AutoSizer >
8489 </ div >
@@ -103,23 +108,30 @@ const copySummary = (data: ReactProfilerData, measure: ReactMeasure) => {
103108const zoomToBatch = (
104109 data : ReactProfilerData ,
105110 measure : ReactMeasure ,
106- syncedHorizontalPanAndZoomViews : HorizontalPanAndZoomView [ ] ,
111+ viewState : ViewState ,
107112) => {
108113 const { batchUID} = measure ;
109114 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+
116+ viewState . updateHorizontalScrollState ( {
117+ offset : startTime ,
118+ length : stopTime - startTime ,
119+ } ) ;
114120} ;
115121
116122type AutoSizedCanvasProps = { |
117123 data : ReactProfilerData ,
118124 height : number ,
125+ viewState : ViewState ,
119126 width : number ,
120127| } ;
121128
122- function AutoSizedCanvas ( { data, height, width} : AutoSizedCanvasProps ) {
129+ function AutoSizedCanvas ( {
130+ data,
131+ height,
132+ viewState,
133+ width,
134+ } : AutoSizedCanvasProps ) {
123135 const canvasRef = useRef < HTMLCanvasElement | null > ( null ) ;
124136
125137 const [ isContextMenuShown , setIsContextMenuShown ] = useState < boolean > ( false ) ;
@@ -137,35 +149,31 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
137149 const componentMeasuresViewRef = useRef ( null ) ;
138150 const reactMeasuresViewRef = useRef ( null ) ;
139151 const flamechartViewRef = useRef ( null ) ;
140- const syncedHorizontalPanAndZoomViewsRef = useRef < HorizontalPanAndZoomView [ ] > (
141- [ ] ,
142- ) ;
143152
144153 const { hideMenu : hideContextMenu } = useContext ( RegistryContext ) ;
145154
146155 useLayoutEffect ( ( ) => {
147156 const surface = surfaceRef . current ;
148157 const defaultFrame = { origin : zeroPoint , size : { width, height} } ;
149158
150- // Clear synced views
151- syncedHorizontalPanAndZoomViewsRef . current = [ ] ;
152-
153- const syncAllHorizontalPanAndZoomViewStates : HorizontalPanAndZoomViewOnChangeCallback = (
154- newState ,
155- triggeringView ? : HorizontalPanAndZoomView ,
156- ) => {
157- // Hide context menu when panning.
159+ // Auto hide context menu when panning.
160+ viewState . onHorizontalScrollStateChange ( scrollState => {
158161 hideContextMenu ( ) ;
162+ } ) ;
159163
160- syncedHorizontalPanAndZoomViewsRef . current . forEach (
161- syncedView =>
162- triggeringView !== syncedView && syncedView . setScrollState ( newState ) ,
163- ) ;
164- } ;
164+ // Initialize horizontal view state
165+ viewState . updateHorizontalScrollState (
166+ clampState ( {
167+ state : viewState . horizontalScrollState ,
168+ minContentLength : data . duration * MIN_ZOOM_LEVEL ,
169+ maxContentLength : data . duration * MAX_ZOOM_LEVEL ,
170+ containerLength : defaultFrame . size . width ,
171+ } ) ,
172+ ) ;
165173
166174 function createViewHelper (
167175 view : View ,
168- resizeLabel : string = '' ,
176+ label : string ,
169177 shouldScrollVertically : boolean = false ,
170178 shouldResizeVertically : boolean = false ,
171179 ) : View {
@@ -175,6 +183,8 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
175183 surface ,
176184 defaultFrame ,
177185 view ,
186+ viewState ,
187+ label ,
178188 ) ;
179189 }
180190
@@ -183,31 +193,39 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
183193 defaultFrame ,
184194 verticalScrollView !== null ? verticalScrollView : view ,
185195 data . duration ,
186- syncAllHorizontalPanAndZoomViewStates ,
196+ viewState ,
187197 ) ;
188198
189- syncedHorizontalPanAndZoomViewsRef . current . push ( horizontalPanAndZoomView ) ;
190-
191- let viewToReturn = horizontalPanAndZoomView ;
199+ let resizableView = null ;
192200 if ( shouldResizeVertically ) {
193- viewToReturn = new ResizableView (
201+ resizableView = new ResizableView (
194202 surface ,
195203 defaultFrame ,
196204 horizontalPanAndZoomView ,
205+ viewState ,
197206 canvasRef ,
198- resizeLabel ,
207+ label ,
199208 ) ;
200209 }
201210
202- return viewToReturn ;
211+ // Restore persisted view state in this specific order
212+ // to allow Resize view to adjust the size of the scroll views first.
213+ if ( resizableView !== null ) {
214+ resizableView . restoreMutableViewState ( ) ;
215+ }
216+ if ( verticalScrollView !== null ) {
217+ verticalScrollView . restoreMutableViewState ( ) ;
218+ }
219+
220+ return resizableView || horizontalPanAndZoomView ;
203221 }
204222
205223 const axisMarkersView = new TimeAxisMarkersView (
206224 surface ,
207225 defaultFrame ,
208226 data . duration ,
209227 ) ;
210- const axisMarkersViewWrapper = createViewHelper ( axisMarkersView ) ;
228+ const axisMarkersViewWrapper = createViewHelper ( axisMarkersView , 'time' ) ;
211229
212230 let userTimingMarksViewWrapper = null ;
213231 if ( data . otherUserTimingMarks . length > 0 ) {
@@ -218,7 +236,10 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
218236 data . duration ,
219237 ) ;
220238 userTimingMarksViewRef . current = userTimingMarksView ;
221- userTimingMarksViewWrapper = createViewHelper ( userTimingMarksView ) ;
239+ userTimingMarksViewWrapper = createViewHelper (
240+ userTimingMarksView ,
241+ 'user timing api' ,
242+ ) ;
222243 }
223244
224245 const nativeEventsView = new NativeEventsView ( surface , defaultFrame , data ) ;
@@ -236,7 +257,10 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
236257 data ,
237258 ) ;
238259 schedulingEventsViewRef . current = schedulingEventsView ;
239- const schedulingEventsViewWrapper = createViewHelper ( schedulingEventsView ) ;
260+ const schedulingEventsViewWrapper = createViewHelper (
261+ schedulingEventsView ,
262+ 'react updates' ,
263+ ) ;
240264
241265 let suspenseEventsViewWrapper = null ;
242266 if ( data . suspenseEvents . length > 0 ) {
@@ -262,7 +286,7 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
262286 reactMeasuresViewRef . current = reactMeasuresView ;
263287 const reactMeasuresViewWrapper = createViewHelper (
264288 reactMeasuresView ,
265- 'react' ,
289+ 'react scheduling ' ,
266290 true ,
267291 true ,
268292 ) ;
@@ -275,7 +299,10 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
275299 data ,
276300 ) ;
277301 componentMeasuresViewRef . current = componentMeasuresView ;
278- componentMeasuresViewWrapper = createViewHelper ( componentMeasuresView ) ;
302+ componentMeasuresViewWrapper = createViewHelper (
303+ componentMeasuresView ,
304+ 'react components' ,
305+ ) ;
279306 }
280307
281308 const flamechartView = new FlamechartView (
@@ -623,11 +650,7 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
623650 { measure !== null && (
624651 < ContextMenuItem
625652 onClick = { ( ) =>
626- zoomToBatch (
627- contextData . data ,
628- measure ,
629- syncedHorizontalPanAndZoomViewsRef . current ,
630- )
653+ zoomToBatch ( contextData . data , measure , viewState )
631654 }
632655 title = "Zoom to batch" >
633656 Zoom to batch
0 commit comments