Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show sample tooltips on sample graph hover #5298

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

canova
Copy link
Member

@canova canova commented Jan 9, 2025

Fixes #3363.

This was requested by multiple people because sometimes it's not clear to users what the squares in the sample graph are. For example latest feedback we got was in #5278. They also said that a tooltip would've helped.

Deploy preview / Production

canova added 4 commits January 9, 2025 16:50
…graph

Previously we were always returning the closest sample to the mouse
hover/click location. Which was okay when we were clicking to select the
boxes before. But now we are also showing tooltips on hover which can be
misleading if they were shown when we are not hovering over them. So to
make this experience less confusing, this commit changes the behavior to
only select or hover a specific sample when the mouse is actually on top
of the sample box that we draw.
Previously we were using the exact same algorithm as the activity graph.
Activity graph tests get the value in between this and the next same
time. But for these tests, we actually want the exact sample time.
@canova canova requested a review from julienw January 9, 2025 15:51
@canova canova force-pushed the tooltip-sample-graph branch from 16bcdf4 to 54e08da Compare January 9, 2025 15:51
@fqueze
Copy link
Contributor

fqueze commented Jan 9, 2025

Looks nice, thanks!

Some feedback (can be handled in follow-ups) :

  • it might make the tooltip even more explicit if we put as the first line of it a line saying "Sample time: "
  • I never noticed it before because we didn't have a way to show the tooltip with the stack for idle samples, but the square next to the "Idle" category is white, but the vertical bar on the left side of the stack frames is grey. The frame "Native event loop idle" should probably have the vertical bar next to it white too.
    image

Copy link
Contributor

@julienw julienw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's great to see this tooltip now, we can always improve the look and fix the small issues later.

I noticed that sometimes hit testing is a bit off: my mouse cursor is clearly on the rectangle, yet the tooltip doesn't appear. It seems to happens at some page zoom levels only. If the fix is easy you can do it now, but if you don't find the source now, it's fine to look at it later.

Also I think the hit target is a bit small and we might want to increase it to some more than just the rectangle. But that could be for later too.

Thanks!

Comment on lines 73 to +77
autoMockCanvasContext();
autoMockElementSize({ width: GRAPH_WIDTH, height: GRAPH_HEIGHT });
autoMockIntersectionObserver();
beforeEach(addRootOverlayElement);
afterEach(removeRootOverlayElement);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kind of feel like this should move to our setup eventually :-)
(not now)

) => void,
+trackName: string,
+timelineType: TimelineType,
implementationFilter: ImplementationFilter,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add + for consistency

Comment on lines +53 to +54
+timelineType: TimelineType,
implementationFilter: ImplementationFilter,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a little performance inefficiency here, that's a reason why in other components, the canvas part is in a separate component compared to the tooltip (see ActivityGraph for example).

Indeed the canvas is redrawn at each render of this component (because it's called in componentDidUpdate). So with these new props, the canvas would be redrawn when timelineType or implementationFilter is changed despite that this doesn't influence the drawing.

The fix is to create a separate component for the canvas. It could be in the same file, I don't mind.


const rect = canvas.getBoundingClientRect();
this.setState({
hoveredPixelState: this._getSampleAtMouseEvent(event),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_getSampleAtMouseEvent only needs pageX (that we have in the state), so we could call it at render time instead of at event time. Very likely this would result in some performance improvement, because React renders less often than move events are triggered.
(although I believe synthetic move events might be throttled already, but likely not as much as rendering)

const r = canvas.getBoundingClientRect();

const x = event.pageX - r.left;
const time = rangeStart + (x / r.width) * (rangeEnd - rangeStart);

const range = [rangeStart, rangeEnd];
const rangeLength = range[1] - range[0];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: rangeEnd - rangeStart

0.8,
trueIntervalPixelWidth * multiplier
);
const drawnSampleWidth = Math.min(drawnIntervalWidth, 10) / 2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it could be better to extract this computation to a separate function, so that we're sure we always have the same one in drawCanvas and here.

const drawnSampleWidth = Math.min(drawnIntervalWidth, 10) / 2;

const maxTimeDistance =
(drawnSampleWidth / 2 / r.width) * (rangeEnd - rangeStart);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use rangeLength

const { rangeStart, rangeEnd, thread, interval } = this.props;
const r = canvas.getBoundingClientRect();

const x = event.pageX - r.left;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

optional: event.offsetX is equal to this value. But I don't remember if it's available on the React's event or if we need to access it with nativeEvent.offsetX. (I think this was the case before but it may be available now)

(optional because we need to call getBoundingClientRect to get the width anyway, so it's only a matter of code style)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add tooltips to the sample graph
3 participants