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

[charts] Improve zoomed highlight behaviour #13868

Merged
merged 14 commits into from
Jul 18, 2024

Conversation

JCQuintas
Copy link
Member

  • BarChart

    • highlight: Move the highlight component inside the clip group
    • tooltip: No change needed, as when the bars are fully outside the tooltip doesn't trigger.
  • LineChart

    • highlight: Move the highlight component inside the clip group
    • tooltip: Left as is. When you are zoomed in you might still want to see the value of what is outside
  • ScatterChart

    • highlight: none
    • tooltip: Changed the voronoi/delauney to only consider the points inside render area

@JCQuintas JCQuintas added enhancement This is not a bug, nor a new feature component: charts This is the name of the generic UI component, not the React module! labels Jul 17, 2024
@JCQuintas JCQuintas self-assigned this Jul 17, 2024
const pointY = getYPosition(y);

if (pointX < left || pointX > left + width || pointY < top || pointY > top + height) {
return [0, 0];
Copy link
Member Author

@JCQuintas JCQuintas Jul 17, 2024

Choose a reason for hiding this comment

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

Not sure this is the best approach. I've tried:

  • Filtering: Messes up index value logic
  • Retuning [NaN, NaN]: Seem to go into an infinite loop
  • Retuning [(+-)Infinity, (+-)Infinity]: In any combination it breaks because the Delaunator logic uses infinity itself to check initial values, so whenever we zoom, we are always on the min or max of the values
  • Returning [0,0]: Seems to work correctly and not affect anything else. I've tried with multiple points combination

Copy link
Member

Choose a reason for hiding this comment

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

You move all the outsider in a trash point (0, 0)

This work as long as there is a point in the drawing area which is closer to the pointer than the top left corner of the SVG.

Basically if you have not point in the drawing area and the red circle, you will start triggering random point.

image

image

I see few options:

  • A proper filter with a mapping from "index after filtering" to "index before filtering"
  • You move point to (-width, -height) instead of (0, 0) The only way for them to be trigger is that all points are outside of the drawing area
  • You don't filter, and if the point is outside you use the neighbors method to implement A* algo and find the closes inside the drawing are (probably too complex)

Copy link
Member Author

Choose a reason for hiding this comment

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

🙃 I was thing [0,0] in dataspace, not svgspace. Feels dumb now. lol

I feel option 2 will be more reasonable, since we won't have to maintain two filters... One of the issue is that Delauney.find() will return an index, if we can't map it between the two of them easily, there wont be a lot of value in that.

@mui-bot
Copy link

mui-bot commented Jul 17, 2024

Deploy preview: https://deploy-preview-13868--material-ui-x.netlify.app/

Generated by 🚫 dangerJS against e5306c8

return 'outside-chart';
}

if (!delauneyRef.current) {
return 'no-point-found';
}

const closestPointIndex = delauneyRef.current.find(svgPoint.x, svgPoint.y);
const closestPointIndex = delauneyRef.current.find(svgPoint.x, svgPoint.y, lastFind.current);
Copy link
Member Author

Choose a reason for hiding this comment

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

Started storing/reusing last index and removed the TODO

@@ -180,11 +192,11 @@ function ChartsVoronoiHandler(props: ChartsVoronoiHandlerProps) {
onItemClick(event, { type: 'scatter', seriesId, dataIndex });
};

element.addEventListener('pointerout', handleMouseOut);
element.addEventListener('pointerleave', handleMouseLeave);
Copy link
Member Author

Choose a reason for hiding this comment

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

out>leave as out triggers on every element inside the chart, rather than leaving the main svg

@JCQuintas JCQuintas requested a review from alexfauquette July 17, 2024 11:19
Comment on lines 166 to 169
<LineHighlightPlot {...lineHighlightPlotProps} />
</g>
<ChartsAxis {...chartsAxisProps} />
<ChartsAxisHighlight {...axisHighlightProps} />
<MarkPlot {...markPlotProps} />
Copy link
Member

Choose a reason for hiding this comment

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

LineHighlightPlot needs to be on top of the MarkPlot. Otherwise, the mark plot will hidde it.
For example
image

It should get similar filtering isInRange as the MarkPlot

https://github.com/mui/mui-x/blob/master/packages/x-charts/src/LineChart/MarkPlot.tsx/#L93-L103

Copy link
Member Author

Choose a reason for hiding this comment

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

Moved the point inside logic to a new function inside the DrawingContext because it was reused in multiple places

const pointY = getYPosition(y);

if (pointX < left || pointX > left + width || pointY < top || pointY > top + height) {
return [0, 0];
Copy link
Member

Choose a reason for hiding this comment

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

You move all the outsider in a trash point (0, 0)

This work as long as there is a point in the drawing area which is closer to the pointer than the top left corner of the SVG.

Basically if you have not point in the drawing area and the red circle, you will start triggering random point.

image

image

I see few options:

  • A proper filter with a mapping from "index after filtering" to "index before filtering"
  • You move point to (-width, -height) instead of (0, 0) The only way for them to be trigger is that all points are outside of the drawing area
  • You don't filter, and if the point is outside you use the neighbors method to implement A* algo and find the closes inside the drawing are (probably too complex)

@JCQuintas JCQuintas requested a review from alexfauquette July 17, 2024 16:00
Copy link
Member

@alexfauquette alexfauquette left a comment

Choose a reason for hiding this comment

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

Nice fix 👌

…r.tsx

Co-authored-by: Alexandre Fauquette <[email protected]>
Signed-off-by: Jose C Quintas Jr <[email protected]>
@JCQuintas JCQuintas enabled auto-merge (squash) July 18, 2024 08:56
@JCQuintas JCQuintas merged commit cd68580 into mui:master Jul 18, 2024
15 checks passed
@JCQuintas JCQuintas deleted the fix-zoom-highlights branch July 18, 2024 09:13
DungTiger pushed a commit to DungTiger/mui-x that referenced this pull request Jul 23, 2024
Signed-off-by: Jose C Quintas Jr <[email protected]>
Co-authored-by: Alexandre Fauquette <[email protected]>
thomasmoon pushed a commit to thomasmoon/mui-x that referenced this pull request Sep 9, 2024
Signed-off-by: Jose C Quintas Jr <[email protected]>
Co-authored-by: Alexandre Fauquette <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: charts This is the name of the generic UI component, not the React module! enhancement This is not a bug, nor a new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants