diff --git a/src/components/network-chart/index.js b/src/components/network-chart/index.js index 132bfd065e..2d0b476cdc 100644 --- a/src/components/network-chart/index.js +++ b/src/components/network-chart/index.js @@ -14,6 +14,10 @@ import { withSize } from '../shared/WithSize'; import { NetworkChartEmptyReasons } from './NetworkChartEmptyReasons'; import { NetworkChartRow } from './NetworkChartRow'; import { ContextMenuTrigger } from '../shared/ContextMenuTrigger'; +import { + TIMELINE_MARGIN_LEFT, + TIMELINE_MARGIN_RIGHT, +} from '../../app-logic/constants'; import { getScrollToSelectionGeneration, @@ -26,6 +30,7 @@ import { changeSelectedNetworkMarker, changeRightClickedMarker, changeHoveredMarker, + changeMouseTimePosition, } from '../../actions/profile-view'; import type { SizeProps } from '../shared/WithSize'; import type { @@ -49,6 +54,7 @@ type DispatchProps = {| +changeSelectedNetworkMarker: typeof changeSelectedNetworkMarker, +changeRightClickedMarker: typeof changeRightClickedMarker, +changeHoveredMarker: typeof changeHoveredMarker, + +changeMouseTimePosition: typeof changeMouseTimePosition, |}; type StateProps = {| @@ -259,6 +265,37 @@ class NetworkChartImpl extends React.PureComponent { changeHoveredMarker(threadsKey, null); }; + _onMouseMove = (event: SyntheticMouseEvent) => { + const { timeRange, width, changeMouseTimePosition } = this.props; + + // Calculate the mouse position relative to the chart area + if (!event.currentTarget) { + return; + } + const rect = event.currentTarget.getBoundingClientRect(); + const mouseX = event.clientX - rect.left; + + // Account for timeline margins (similar to marker chart logic) + const chartWidth = width - TIMELINE_MARGIN_LEFT - TIMELINE_MARGIN_RIGHT; + const adjustedMouseX = mouseX - TIMELINE_MARGIN_LEFT; + + // Calculate the time position + const { start: rangeStart, end: rangeEnd } = timeRange; + const rangeLength = rangeEnd - rangeStart; + const xInUnitInterval = adjustedMouseX / chartWidth; + + if (xInUnitInterval < 0 || xInUnitInterval > 1) { + changeMouseTimePosition(null); + } else { + const xInTime = rangeStart + xInUnitInterval * rangeLength; + changeMouseTimePosition(xInTime); + } + }; + + _onMouseLeave = () => { + this.props.changeMouseTimePosition(null); + }; + _shouldDisplayTooltips = () => this.props.rightClickedMarkerIndex === null; _renderRow = (markerIndex: MarkerIndex, index: number): React.Node => { @@ -327,6 +364,8 @@ class NetworkChartImpl extends React.PureComponent { id="network-chart-tab" role="tabpanel" aria-labelledby="network-chart-tab-button" + onMouseMove={this._onMouseMove} + onMouseLeave={this._onMouseLeave} > {markerIndexes.length === 0 ? ( @@ -394,6 +433,7 @@ export const NetworkChart = explicitConnect< changeSelectedNetworkMarker, changeRightClickedMarker, changeHoveredMarker, + changeMouseTimePosition, }, component: withSize(NetworkChartImpl), }); diff --git a/src/test/components/NetworkChart.test.js b/src/test/components/NetworkChart.test.js index 533ebba7bb..cc048eb813 100644 --- a/src/test/components/NetworkChart.test.js +++ b/src/test/components/NetworkChart.test.js @@ -777,4 +777,38 @@ describe('calltree/ProfileCallTreeView navigation keys', () => { initialScrollGeneration ); }); + + it('changes the mouse time position when the mouse moves', function () { + const { getState, container } = setupWithPayload(getNetworkMarkers()); + + // Expect the mouseTimePosition to not be set at the beginning of the test. + expect(getState().profileView.viewOptions.mouseTimePosition).toBeNull(); + + const networkChart = ensureExists( + container.querySelector('.networkChart'), + 'Could not find the network chart element' + ); + + // Move the mouse over the network chart, ensure mouseTimePosition is set. + fireEvent.mouseMove(networkChart, { + clientX: TIMELINE_MARGIN_LEFT + 100, // Position within the chart area + clientY: 100, + }); + const mouseTimePosition = + getState().profileView.viewOptions.mouseTimePosition; + expect(typeof mouseTimePosition).toEqual('number'); + + // Move the mouse to a different position, ensure mouseTimePosition changed. + fireEvent.mouseMove(networkChart, { + clientX: TIMELINE_MARGIN_LEFT + 150, // Different position within chart area + clientY: 100, + }); + expect(getState().profileView.viewOptions.mouseTimePosition).not.toEqual( + mouseTimePosition + ); + + // Move the mouse out of the network chart, ensure mouseTimePosition is no longer set. + fireEvent.mouseLeave(networkChart); + expect(getState().profileView.viewOptions.mouseTimePosition).toBeNull(); + }); });