@samitouri / QOS-React / commits / d95434082f

Scheduling profiler: UX tweaks (#21971)

Brian Vaughn committed Jul 27, 2021 at 14:34 UTC d95434082f9fe0c612d20a6779e78b818154653b
10 files changed +75 -156
packages/react-devtools-scheduling-profiler/src/CanvasPage.js
+1 -1
@@ -507,7 +507,7 @@ function AutoSizedCanvas({data, height, width}: AutoSizedCanvasProps) {
507 );
508 }}
509 </ContextMenu>
510 - {!isContextMenuShown && (
510 + {!isContextMenuShown && !surfaceRef.current.hasActiveView() && (
511 <EventTooltip
512 data={data}
513 hoveredEvent={hoveredEvent}
packages/react-devtools-scheduling-profiler/src/content-views/FlamechartView.js
+5 -13
@@ -17,7 +17,7 @@ import type {
17 MouseMoveInteraction,
18 Rect,
19 Size,
20 - ViewRef,
20 + ViewRefs,
21 } from '../view-base';
22
23 import {
@@ -246,11 +246,7 @@ class FlamechartStackLayerView extends View {
246 /**
247 * @private
248 */
249 - _handleMouseMove(
250 - interaction: MouseMoveInteraction,
251 - activeViewRef: ViewRef,
252 - hoveredViewRef: ViewRef,
253 - ) {
249 + _handleMouseMove(interaction: MouseMoveInteraction, viewRefs: ViewRefs) {
250 const {_stackLayer, frame, _intrinsicSize, _onHover, visibleArea} = this;
251 const {location} = interaction.payload;
252 if (!_onHover || !rectContainsPoint(location, visibleArea)) {
@@ -270,7 +266,7 @@ class FlamechartStackLayerView extends View {
266 const x = Math.floor(timestampToPosition(timestamp, scaleFactor, frame));
267 if (x <= location.x && x + width >= location.x) {
268 this.currentCursor = 'pointer';
273 - hoveredViewRef.current = this;
269 + viewRefs.hoveredView = this;
270 _onHover(flamechartStackFrame);
271 return;
272 }
@@ -287,14 +283,10 @@ class FlamechartStackLayerView extends View {
283
284 _didGrab: boolean = false;
285
290 - handleInteraction(
291 - interaction: Interaction,
292 - activeViewRef: ViewRef,
293 - hoveredViewRef: ViewRef,
294 - ) {
286 + handleInteraction(interaction: Interaction, viewRefs: ViewRefs) {
287 switch (interaction.type) {
288 case 'mousemove':
297 - this._handleMouseMove(interaction, activeViewRef, hoveredViewRef);
289 + this._handleMouseMove(interaction, viewRefs);
290 break;
291 }
292 }
packages/react-devtools-scheduling-profiler/src/content-views/NativeEventsView.js
+5 -13
@@ -13,7 +13,7 @@ import type {
13 MouseMoveInteraction,
14 Rect,
15 Size,
16 - ViewRef,
16 + ViewRefs,
17 } from '../view-base';
18
19 import {
@@ -255,11 +255,7 @@ export class NativeEventsView extends View {
255 /**
256 * @private
257 */
258 - _handleMouseMove(
259 - interaction: MouseMoveInteraction,
260 - activeViewRef: ViewRef,
261 - hoveredViewRef: ViewRef,
262 - ) {
258 + _handleMouseMove(interaction: MouseMoveInteraction, viewRefs: ViewRefs) {
259 const {frame, _intrinsicSize, onHover, visibleArea} = this;
260 if (!onHover) {
261 return;
@@ -290,7 +286,7 @@ export class NativeEventsView extends View {
286 ) {
287 this.currentCursor = 'pointer';
288
293 - hoveredViewRef.current = this;
289 + viewRefs.hoveredView = this;
290
291 onHover(nativeEvent);
292 return;
@@ -301,14 +297,10 @@ export class NativeEventsView extends View {
297 onHover(null);
298 }
299
304 - handleInteraction(
305 - interaction: Interaction,
306 - activeViewRef: ViewRef,
307 - hoveredViewRef: ViewRef,
308 - ) {
300 + handleInteraction(interaction: Interaction, viewRefs: ViewRefs) {
301 switch (interaction.type) {
302 case 'mousemove':
311 - this._handleMouseMove(interaction, activeViewRef, hoveredViewRef);
303 + this._handleMouseMove(interaction, viewRefs);
304 break;
305 }
306 }
packages/react-devtools-scheduling-profiler/src/content-views/ReactEventsView.js
+5 -13
@@ -13,7 +13,7 @@ import type {
13 MouseMoveInteraction,
14 Rect,
15 Size,
16 - ViewRef,
16 + ViewRefs,
17 } from '../view-base';
18
19 import {
@@ -231,11 +231,7 @@ export class ReactEventsView extends View {
231 /**
232 * @private
233 */
234 - _handleMouseMove(
235 - interaction: MouseMoveInteraction,
236 - activeViewRef: ViewRef,
237 - hoveredViewRef: ViewRef,
238 - ) {
234 + _handleMouseMove(interaction: MouseMoveInteraction, viewRefs: ViewRefs) {
235 const {frame, onHover, visibleArea} = this;
236 if (!onHover) {
237 return;
@@ -271,7 +267,7 @@ export class ReactEventsView extends View {
267 hoverTimestamp <= timestamp + eventTimestampAllowance
268 ) {
269 this.currentCursor = 'pointer';
274 - hoveredViewRef.current = this;
270 + viewRefs.hoveredView = this;
271 onHover(event);
272 return;
273 }
@@ -280,14 +276,10 @@ export class ReactEventsView extends View {
276 onHover(null);
277 }
278
283 - handleInteraction(
284 - interaction: Interaction,
285 - activeViewRef: ViewRef,
286 - hoveredViewRef: ViewRef,
287 - ) {
279 + handleInteraction(interaction: Interaction, viewRefs: ViewRefs) {
280 switch (interaction.type) {
281 case 'mousemove':
290 - this._handleMouseMove(interaction, activeViewRef, hoveredViewRef);
282 + this._handleMouseMove(interaction, viewRefs);
283 break;
284 }
285 }
packages/react-devtools-scheduling-profiler/src/content-views/ReactMeasuresView.js
+5 -13
@@ -13,7 +13,7 @@ import type {
13 MouseMoveInteraction,
14 Rect,
15 Size,
16 - ViewRef,
16 + ViewRefs,
17 } from '../view-base';
18
19 import {
@@ -256,11 +256,7 @@ export class ReactMeasuresView extends View {
256 /**
257 * @private
258 */
259 - _handleMouseMove(
260 - interaction: MouseMoveInteraction,
261 - activeViewRef: ViewRef,
262 - hoveredViewRef: ViewRef,
263 - ) {
259 + _handleMouseMove(interaction: MouseMoveInteraction, viewRefs: ViewRefs) {
260 const {
261 frame,
262 _intrinsicSize,
@@ -311,7 +307,7 @@ export class ReactMeasuresView extends View {
307 hoverTimestamp <= timestamp + duration
308 ) {
309 this.currentCursor = 'pointer';
314 - hoveredViewRef.current = this;
310 + viewRefs.hoveredView = this;
311 onHover(measure);
312 return;
313 }
@@ -320,14 +316,10 @@ export class ReactMeasuresView extends View {
316 onHover(null);
317 }
318
323 - handleInteraction(
324 - interaction: Interaction,
325 - activeViewRef: ViewRef,
326 - hoveredViewRef: ViewRef,
327 - ) {
319 + handleInteraction(interaction: Interaction, viewRefs: ViewRefs) {
320 switch (interaction.type) {
321 case 'mousemove':
330 - this._handleMouseMove(interaction, activeViewRef, hoveredViewRef);
322 + this._handleMouseMove(interaction, viewRefs);
323 break;
324 }
325 }
packages/react-devtools-scheduling-profiler/src/content-views/UserTimingMarksView.js
+5 -13
@@ -13,7 +13,7 @@ import type {
13 MouseMoveInteraction,
14 Rect,
15 Size,
16 - ViewRef,
16 + ViewRefs,
17 } from '../view-base';
18
19 import {
@@ -191,11 +191,7 @@ export class UserTimingMarksView extends View {
191 /**
192 * @private
193 */
194 - _handleMouseMove(
195 - interaction: MouseMoveInteraction,
196 - activeViewRef: ViewRef,
197 - hoveredViewRef: ViewRef,
198 - ) {
194 + _handleMouseMove(interaction: MouseMoveInteraction, viewRefs: ViewRefs) {
195 const {frame, onHover, visibleArea} = this;
196 if (!onHover) {
197 return;
@@ -229,7 +225,7 @@ export class UserTimingMarksView extends View {
225 hoverTimestamp <= timestamp + markTimestampAllowance
226 ) {
227 this.currentCursor = 'pointer';
232 - hoveredViewRef.current = this;
228 + viewRefs.hoveredView = this;
229 onHover(mark);
230 return;
231 }
@@ -238,14 +234,10 @@ export class UserTimingMarksView extends View {
234 onHover(null);
235 }
236
241 - handleInteraction(
242 - interaction: Interaction,
243 - activeViewRef: ViewRef,
244 - hoveredViewRef: ViewRef,
245 - ) {
237 + handleInteraction(interaction: Interaction, viewRefs: ViewRefs) {
238 switch (interaction.type) {
239 case 'mousemove':
248 - this._handleMouseMove(interaction, activeViewRef, hoveredViewRef);
240 + this._handleMouseMove(interaction, viewRefs);
241 break;
242 }
243 }
packages/react-devtools-scheduling-profiler/src/view-base/HorizontalPanAndZoomView.js
+13 -29
@@ -19,7 +19,7 @@ import type {
19 } from './useCanvasInteraction';
20 import type {Rect} from './geometry';
21 import type {ScrollState} from './utils/scrollState';
22 -import type {ViewRef} from './Surface';
22 +import type {ViewRefs} from './Surface';
23
24 import {Surface} from './Surface';
25 import {View} from './View';
@@ -156,34 +156,26 @@ export class HorizontalPanAndZoomView extends View {
156 this._setScrollState(newState);
157 }
158
159 - _handleMouseDown(
160 - interaction: MouseDownInteraction,
161 - activeViewRef: ViewRef,
162 - hoveredViewRef: ViewRef,
163 - ) {
159 + _handleMouseDown(interaction: MouseDownInteraction, viewRefs: ViewRefs) {
160 if (rectContainsPoint(interaction.payload.location, this.frame)) {
161 this._isPanning = true;
162
167 - activeViewRef.current = this;
163 + viewRefs.activeView = this;
164
165 this.currentCursor = 'grabbing';
166 }
167 }
168
173 - _handleMouseMove(
174 - interaction: MouseMoveInteraction,
175 - activeViewRef: ViewRef,
176 - hoveredViewRef: ViewRef,
177 - ) {
169 + _handleMouseMove(interaction: MouseMoveInteraction, viewRefs: ViewRefs) {
170 const isHovered = rectContainsPoint(
171 interaction.payload.location,
172 this.frame,
173 );
174 if (isHovered) {
183 - hoveredViewRef.current = this;
175 + viewRefs.hoveredView = this;
176 }
177
186 - if (activeViewRef.current === this) {
178 + if (viewRefs.activeView === this) {
179 this.currentCursor = 'grabbing';
180 } else if (isHovered) {
181 this.currentCursor = 'grab';
@@ -200,17 +192,13 @@ export class HorizontalPanAndZoomView extends View {
192 this._setStateAndInformCallbacksIfChanged(newState);
193 }
194
203 - _handleMouseUp(
204 - interaction: MouseUpInteraction,
205 - activeViewRef: ViewRef,
206 - hoveredViewRef: ViewRef,
207 - ) {
195 + _handleMouseUp(interaction: MouseUpInteraction, viewRefs: ViewRefs) {
196 if (this._isPanning) {
197 this._isPanning = false;
198 }
199
212 - if (activeViewRef.current === this) {
213 - activeViewRef.current = null;
200 + if (viewRefs.activeView === this) {
201 + viewRefs.activeView = null;
202 }
203 }
204
@@ -273,20 +261,16 @@ export class HorizontalPanAndZoomView extends View {
261 this._setStateAndInformCallbacksIfChanged(newState);
262 }
263
276 - handleInteraction(
277 - interaction: Interaction,
278 - activeViewRef: ViewRef,
279 - hoveredViewRef: ViewRef,
280 - ) {
264 + handleInteraction(interaction: Interaction, viewRefs: ViewRefs) {
265 switch (interaction.type) {
266 case 'mousedown':
283 - this._handleMouseDown(interaction, activeViewRef, hoveredViewRef);
267 + this._handleMouseDown(interaction, viewRefs);
268 break;
269 case 'mousemove':
286 - this._handleMouseMove(interaction, activeViewRef, hoveredViewRef);
270 + this._handleMouseMove(interaction, viewRefs);
271 break;
272 case 'mouseup':
289 - this._handleMouseUp(interaction, activeViewRef, hoveredViewRef);
273 + this._handleMouseUp(interaction, viewRefs);
274 break;
275 case 'wheel-plain':
276 this._handleWheelPlain(interaction);
packages/react-devtools-scheduling-profiler/src/view-base/ResizableSplitView.js
+14 -34
@@ -14,7 +14,7 @@ import type {
14 MouseUpInteraction,
15 } from './useCanvasInteraction';
16 import type {Rect, Size} from './geometry';
17 -import type {ViewRef} from './Surface';
17 +import type {ViewRefs} from './Surface';
18
19 import {COLORS} from '../content-views/constants';
20 import nullthrows from 'nullthrows';
@@ -83,36 +83,28 @@ class ResizeBar extends View {
83 this._updateColor();
84 }
85
86 - _handleMouseDown(
87 - interaction: MouseDownInteraction,
88 - activeViewRef: ViewRef,
89 - hoveredViewRef: ViewRef,
90 - ) {
86 + _handleMouseDown(interaction: MouseDownInteraction, viewRefs: ViewRefs) {
87 const cursorInView = rectContainsPoint(
88 interaction.payload.location,
89 this.frame,
90 );
91 if (cursorInView) {
92 this._setInteractionState('dragging');
97 - activeViewRef.current = this;
93 + viewRefs.activeView = this;
94 }
95 }
96
101 - _handleMouseMove(
102 - interaction: MouseMoveInteraction,
103 - activeViewRef: ViewRef,
104 - hoveredViewRef: ViewRef,
105 - ) {
97 + _handleMouseMove(interaction: MouseMoveInteraction, viewRefs: ViewRefs) {
98 const cursorInView = rectContainsPoint(
99 interaction.payload.location,
100 this.frame,
101 );
102
111 - if (cursorInView || activeViewRef.current === this) {
103 + if (cursorInView || viewRefs.activeView === this) {
104 this.currentCursor = 'ns-resize';
105 }
106 if (cursorInView) {
115 - hoveredViewRef.current = this;
107 + viewRefs.hoveredView = this;
108 }
109
110 if (this._interactionState === 'dragging') {
@@ -121,11 +113,7 @@ class ResizeBar extends View {
113 this._setInteractionState(cursorInView ? 'hovered' : 'normal');
114 }
115
124 - _handleMouseUp(
125 - interaction: MouseUpInteraction,
126 - activeViewRef: ViewRef,
127 - hoveredViewRef: ViewRef,
128 - ) {
116 + _handleMouseUp(interaction: MouseUpInteraction, viewRefs: ViewRefs) {
117 const cursorInView = rectContainsPoint(
118 interaction.payload.location,
119 this.frame,
@@ -134,25 +122,21 @@ class ResizeBar extends View {
122 this._setInteractionState(cursorInView ? 'hovered' : 'normal');
123 }
124
137 - if (activeViewRef.current === this) {
138 - activeViewRef.current = null;
125 + if (viewRefs.activeView === this) {
126 + viewRefs.activeView = null;
127 }
128 }
129
142 - handleInteraction(
143 - interaction: Interaction,
144 - activeViewRef: ViewRef,
145 - hoveredViewRef: ViewRef,
146 - ) {
130 + handleInteraction(interaction: Interaction, viewRefs: ViewRefs) {
131 switch (interaction.type) {
132 case 'mousedown':
149 - this._handleMouseDown(interaction, activeViewRef, hoveredViewRef);
133 + this._handleMouseDown(interaction, viewRefs);
134 return;
135 case 'mousemove':
152 - this._handleMouseMove(interaction, activeViewRef, hoveredViewRef);
136 + this._handleMouseMove(interaction, viewRefs);
137 return;
138 case 'mouseup':
155 - this._handleMouseUp(interaction, activeViewRef, hoveredViewRef);
139 + this._handleMouseUp(interaction, viewRefs);
140 return;
141 }
142 }
@@ -339,11 +323,7 @@ export class ResizableSplitView extends View {
323 }
324 }
325
342 - handleInteraction(
343 - interaction: Interaction,
344 - activeViewRef: ViewRef,
345 - hoveredViewRef: ViewRef,
346 - ) {
326 + handleInteraction(interaction: Interaction, viewRefs: ViewRefs) {
327 switch (interaction.type) {
328 case 'mousedown':
329 this._handleMouseDown(interaction);
packages/react-devtools-scheduling-profiler/src/view-base/Surface.js
+17 -13
@@ -10,13 +10,15 @@
10 import type {Interaction} from './useCanvasInteraction';
11 import type {Size} from './geometry';
12
13 -import {createRef} from 'react';
13 import memoize from 'memoize-one';
14
15 import {View} from './View';
16 import {zeroPoint} from './geometry';
17
19 -export type ViewRef = {|current: View | null|};
18 +export type ViewRefs = {|
19 + activeView: View | null,
20 + hoveredView: View | null,
21 +|};
22
23 // hidpi canvas: https://www.html5rocks.com/en/tutorials/canvas/hidpi/
24 function configureRetinaCanvas(canvas, height, width) {
@@ -55,8 +57,14 @@ export class Surface {
57 _context: ?CanvasRenderingContext2D;
58 _canvasSize: ?Size;
59
58 - _activeViewRef: ViewRef = createRef();
59 - _hoveredViewRef: ViewRef = createRef();
60 + _viewRefs: ViewRefs = {
61 + activeView: null,
62 + hoveredView: null,
63 + };
64 +
65 + hasActiveView(): boolean {
66 + return this._viewRefs.activeView !== null;
67 + }
68
69 setCanvas(canvas: HTMLCanvasElement, canvasSize: Size) {
70 this._context = getCanvasContext(
@@ -88,17 +96,14 @@ export class Surface {
96 }
97
98 getCurrentCursor(): string | null {
91 - const activeView = this._activeViewRef.current;
99 + const {activeView, hoveredView} = this._viewRefs;
100 if (activeView !== null) {
101 return activeView.currentCursor;
102 + } else if (hoveredView !== null) {
103 + return hoveredView.currentCursor;
104 } else {
95 - const hoveredView = this._hoveredViewRef.current;
96 - if (hoveredView !== null) {
97 - return hoveredView.currentCursor;
98 - }
105 + return null;
106 }
100 -
101 - return null;
107 }
108
109 handleInteraction(interaction: Interaction) {
@@ -107,8 +112,7 @@ export class Surface {
112 }
113 this.rootView.handleInteractionAndPropagateToSubviews(
114 interaction,
110 - this._activeViewRef,
111 - this._hoveredViewRef,
115 + this._viewRefs,
116 );
117 }
118 }
packages/react-devtools-scheduling-profiler/src/view-base/View.js
+5 -14
@@ -10,7 +10,7 @@
10 import type {Interaction} from './useCanvasInteraction';
11 import type {Rect, Size} from './geometry';
12 import type {Layouter} from './layouter';
13 -import type {ViewRef} from './Surface';
13 +import type {ViewRefs} from './Surface';
14
15 import {Surface} from './Surface';
16 import {
@@ -256,11 +256,7 @@ export class View {
256 // Internal note: Do not call directly! Use
257 // `handleInteractionAndPropagateToSubviews` so that interactions are
258 // propagated to subviews.
259 - handleInteraction(
260 - interaction: Interaction,
261 - activeViewRef: ViewRef,
262 - hoveredViewRef: ViewRef,
263 - ) {}
259 + handleInteraction(interaction: Interaction, viewRefs: ViewRefs) {}
260
261 /**
262 * Handle an `interaction` and propagates it to all of this view's
@@ -274,16 +270,11 @@ export class View {
270 */
271 handleInteractionAndPropagateToSubviews(
272 interaction: Interaction,
277 - activeViewRef: ViewRef,
278 - hoveredViewRef: ViewRef,
273 + viewRefs: ViewRefs,
274 ) {
280 - this.handleInteraction(interaction, activeViewRef, hoveredViewRef);
275 + this.handleInteraction(interaction, viewRefs);
276 this.subviews.forEach(subview =>
282 - subview.handleInteractionAndPropagateToSubviews(
283 - interaction,
284 - activeViewRef,
285 - hoveredViewRef,
286 - ),
277 + subview.handleInteractionAndPropagateToSubviews(interaction, viewRefs),
278 );
279 }
280 }