Skip to content

Commit 927870f

Browse files
authored
Show the vertical ruler in the timeline when hovering the network chart (#5548)
When hovering over the network chart, display a vertical ruler in the timeline to match the behavior of marker chart and stack chart. This makes it easier to correlate slow network request handling with high CPU use for other reasons in the timeline.
1 parent 333baf8 commit 927870f

File tree

2 files changed

+74
-0
lines changed

2 files changed

+74
-0
lines changed

src/components/network-chart/index.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ import { withSize } from '../shared/WithSize';
1414
import { NetworkChartEmptyReasons } from './NetworkChartEmptyReasons';
1515
import { NetworkChartRow } from './NetworkChartRow';
1616
import { ContextMenuTrigger } from '../shared/ContextMenuTrigger';
17+
import {
18+
TIMELINE_MARGIN_LEFT,
19+
TIMELINE_MARGIN_RIGHT,
20+
} from '../../app-logic/constants';
1721

1822
import {
1923
getScrollToSelectionGeneration,
@@ -26,6 +30,7 @@ import {
2630
changeSelectedNetworkMarker,
2731
changeRightClickedMarker,
2832
changeHoveredMarker,
33+
changeMouseTimePosition,
2934
} from '../../actions/profile-view';
3035
import type { SizeProps } from '../shared/WithSize';
3136
import type {
@@ -49,6 +54,7 @@ type DispatchProps = {|
4954
+changeSelectedNetworkMarker: typeof changeSelectedNetworkMarker,
5055
+changeRightClickedMarker: typeof changeRightClickedMarker,
5156
+changeHoveredMarker: typeof changeHoveredMarker,
57+
+changeMouseTimePosition: typeof changeMouseTimePosition,
5258
|};
5359

5460
type StateProps = {|
@@ -259,6 +265,37 @@ class NetworkChartImpl extends React.PureComponent<Props> {
259265
changeHoveredMarker(threadsKey, null);
260266
};
261267

268+
_onMouseMove = (event: SyntheticMouseEvent<Element>) => {
269+
const { timeRange, width, changeMouseTimePosition } = this.props;
270+
271+
// Calculate the mouse position relative to the chart area
272+
if (!event.currentTarget) {
273+
return;
274+
}
275+
const rect = event.currentTarget.getBoundingClientRect();
276+
const mouseX = event.clientX - rect.left;
277+
278+
// Account for timeline margins (similar to marker chart logic)
279+
const chartWidth = width - TIMELINE_MARGIN_LEFT - TIMELINE_MARGIN_RIGHT;
280+
const adjustedMouseX = mouseX - TIMELINE_MARGIN_LEFT;
281+
282+
// Calculate the time position
283+
const { start: rangeStart, end: rangeEnd } = timeRange;
284+
const rangeLength = rangeEnd - rangeStart;
285+
const xInUnitInterval = adjustedMouseX / chartWidth;
286+
287+
if (xInUnitInterval < 0 || xInUnitInterval > 1) {
288+
changeMouseTimePosition(null);
289+
} else {
290+
const xInTime = rangeStart + xInUnitInterval * rangeLength;
291+
changeMouseTimePosition(xInTime);
292+
}
293+
};
294+
295+
_onMouseLeave = () => {
296+
this.props.changeMouseTimePosition(null);
297+
};
298+
262299
_shouldDisplayTooltips = () => this.props.rightClickedMarkerIndex === null;
263300

264301
_renderRow = (markerIndex: MarkerIndex, index: number): React.Node => {
@@ -327,6 +364,8 @@ class NetworkChartImpl extends React.PureComponent<Props> {
327364
id="network-chart-tab"
328365
role="tabpanel"
329366
aria-labelledby="network-chart-tab-button"
367+
onMouseMove={this._onMouseMove}
368+
onMouseLeave={this._onMouseLeave}
330369
>
331370
<NetworkSettings />
332371
{markerIndexes.length === 0 ? (
@@ -394,6 +433,7 @@ export const NetworkChart = explicitConnect<
394433
changeSelectedNetworkMarker,
395434
changeRightClickedMarker,
396435
changeHoveredMarker,
436+
changeMouseTimePosition,
397437
},
398438
component: withSize(NetworkChartImpl),
399439
});

src/test/components/NetworkChart.test.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,4 +777,38 @@ describe('calltree/ProfileCallTreeView navigation keys', () => {
777777
initialScrollGeneration
778778
);
779779
});
780+
781+
it('changes the mouse time position when the mouse moves', function () {
782+
const { getState, container } = setupWithPayload(getNetworkMarkers());
783+
784+
// Expect the mouseTimePosition to not be set at the beginning of the test.
785+
expect(getState().profileView.viewOptions.mouseTimePosition).toBeNull();
786+
787+
const networkChart = ensureExists(
788+
container.querySelector('.networkChart'),
789+
'Could not find the network chart element'
790+
);
791+
792+
// Move the mouse over the network chart, ensure mouseTimePosition is set.
793+
fireEvent.mouseMove(networkChart, {
794+
clientX: TIMELINE_MARGIN_LEFT + 100, // Position within the chart area
795+
clientY: 100,
796+
});
797+
const mouseTimePosition =
798+
getState().profileView.viewOptions.mouseTimePosition;
799+
expect(typeof mouseTimePosition).toEqual('number');
800+
801+
// Move the mouse to a different position, ensure mouseTimePosition changed.
802+
fireEvent.mouseMove(networkChart, {
803+
clientX: TIMELINE_MARGIN_LEFT + 150, // Different position within chart area
804+
clientY: 100,
805+
});
806+
expect(getState().profileView.viewOptions.mouseTimePosition).not.toEqual(
807+
mouseTimePosition
808+
);
809+
810+
// Move the mouse out of the network chart, ensure mouseTimePosition is no longer set.
811+
fireEvent.mouseLeave(networkChart);
812+
expect(getState().profileView.viewOptions.mouseTimePosition).toBeNull();
813+
});
780814
});

0 commit comments

Comments
 (0)