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
}