mui-x icon indicating copy to clipboard operation
mui-x copied to clipboard

[charts] Add control to the axis highlight

Open alexfauquette opened this issue 7 months ago • 6 comments

The idea is to add an onXAxisInteraction that provides meaning full information about where the pointer is compared to x-axes.

Implementation

For now it's only trigger by pointerMove event. Which has a known limitation: It the developer has some logic that modifies the data the onXAxisInteraction will not be trigger by the modification.

For example, if the pointer moves over the last value of the x-axis. we call onXAxisInteraction with this data index. When the last item get removed by some async call, the item does not exist anymore, and we end up in a weird situation.

A potential solution is to apply the same logic when updating axes: compute interaction values before/after the axis modification and trigger the onXAxisInteraction if needed (to explore)

DX

The onXAxisInteraction support multiple axes. That's not super useful for highlight that only accept one. But it will be usefull to control that axis tooltip.

The axis interaction contains both dataIndex and value. The usecases are the following:

  • If axis has data, the dataIndex is the source of truth.
  • If axis has no data (for example the y-axis on line chart, of any axis on scatter chart) the value is needed.

I'm not sure it's a good idea to have both. I'm thinking about only supporting the dataIndex, because axes without data are useless for the axis-tooltip. And the axis highlight is overcomplicated and wem behavior can be obtained by implementing the last demo of Custom components - Scales (Coordinate to value )

alexfauquette avatar May 19 '25 14:05 alexfauquette

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

Updated pages:

Bundle size report

Total Size Change: 🔺+49KB(+0.37%) - Total Gzip Change: 🔺+15.7KB(+0.39%) Files: 122 total (0 added, 0 removed, 37 changed)

Show details for 100 more bundles (22 more not shown)

@mui/x-charts-pro/ChartContainerProparsed: 🔺+3.88KB(+2.20%) gzip: 🔺+1.2KB(+2.16%) @mui/x-charts/ChartContainerparsed: 🔺+3.87KB(+2.64%) gzip: 🔺+1.08KB(+2.39%) @mui/x-charts/Gaugeparsed: 🔺+3.76KB(+2.68%) gzip: 🔺+1.04KB(+2.37%) @mui/x-charts-pro/ChartDataProviderProparsed: 🔺+3.75KB(+2.22%) gzip: 🔺+1.33KB(+2.50%) @mui/x-charts/ChartDataProviderparsed: 🔺+3.74KB(+2.68%) gzip: 🔺+1.11KB(+2.58%) @mui/x-charts-proparsed: 🔺+2.4KB(+0.63%) gzip: 🔺+750B(+0.65%) @mui/x-chartsparsed: 🔺+2.4KB(+0.79%) gzip: 🔺+755B(+0.83%) @mui/x-charts-pro/LineChartProparsed: 🔺+2.34KB(+0.84%) gzip: 🔺+648B(+0.74%) @mui/x-charts/LineChartparsed: 🔺+2.34KB(+1.04%) gzip: 🔺+842B(+1.22%) @mui/x-charts/ScatterChartparsed: 🔺+2.15KB(+1.11%) gzip: 🔺+712B(+1.19%) @mui/x-charts-pro/BarChartProparsed: 🔺+2.15KB(+0.78%) gzip: 🔺+617B(+0.72%) @mui/x-charts-pro/FunnelChartparsed: 🔺+2.15KB(+0.88%) gzip: 🔺+772B(+1.03%) @mui/x-charts-pro/ScatterChartProparsed: 🔺+2.15KB(+0.80%) gzip: 🔺+736B(+0.87%) @mui/x-charts/BarChartparsed: 🔺+2.15KB(+1.03%) gzip: 🔺+622B(+0.96%) @mui/x-charts/SparkLineChartparsed: 🔺+2.07KB(+0.99%) gzip: 🔺+635B(+0.99%) @mui/x-charts-pro/PieChartProparsed: 🔺+1.42KB(+0.61%) gzip: 🔺+490B(+0.68%) @mui/x-charts/PieChartparsed: 🔺+1.41KB(+0.72%) gzip: 🔺+436B(+0.72%) @mui/x-charts-pro/Heatmapparsed: 🔺+1.29KB(+0.56%) gzip: 🔺+386B(+0.54%) @mui/x-charts/RadarChartparsed: 🔺+1.28KB(+0.67%) gzip: 🔺+524B(+0.89%) @mui/x-charts-pro/RadarChartProparsed: 🔺+1.28KB(+0.63%) gzip: 🔺+719B(+1.14%) @mui/x-charts/ChartsAxisHighlightparsed: 🔺+778B(+1.27%) gzip: 🔺+205B(+0.95%) @mui/x-charts/ChartsTooltipparsed: 🔺+226B(+0.29%) gzip: 🔺+71B(+0.27%) @mui/x-charts-pro/ChartsToolbarProparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts-pro/ChartZoomSliderparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsAxisparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsClipPathparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsGridparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsLabelparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsLegendparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsLocalizationProviderparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsOverlayparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsReferenceLineparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsSurfaceparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsTextparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsXAxisparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/ChartsYAxisparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-charts/Toolbarparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-data-gridparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-data-grid-premiumparsed: 0B(0.00%) gzip: ▼-1B(0.00%) @mui/x-data-grid-premium/DataGridPremiumparsed: 0B(0.00%) gzip: ▼-2B(0.00%) @mui/x-data-grid-proparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-data-grid-pro/DataGridProparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-data-grid/DataGridparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickersparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-proparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/AdapterDateFnsparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/AdapterDateFnsJalaliparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/AdapterDayjsparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/AdapterLuxonparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/AdapterMomentparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/AdapterMomentHijriparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/AdapterMomentJalaaliparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/DateRangeCalendarparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/DateRangePickerparsed: 0B(0.00%) gzip: ▼-3B(-0.01%) @mui/x-date-pickers-pro/DateRangePickerDayparsed: 0B(0.00%) gzip: 🔺+3B(+0.04%) @mui/x-date-pickers-pro/DateRangePickerDay2parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/DateTimeRangePickerparsed: 0B(0.00%) gzip: ▼-1B(0.00%) @mui/x-date-pickers-pro/DesktopDateRangePickerparsed: 0B(0.00%) gzip: ▼-1B(0.00%) @mui/x-date-pickers-pro/DesktopDateTimeRangePickerparsed: 0B(0.00%) gzip: ▼-1B(0.00%) @mui/x-date-pickers-pro/DesktopTimeRangePickerparsed: 0B(0.00%) gzip: ▼-1B(0.00%) @mui/x-date-pickers-pro/LocalizationProviderparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/MobileDateRangePickerparsed: 0B(0.00%) gzip: ▼-3B(-0.01%) @mui/x-date-pickers-pro/MobileDateTimeRangePickerparsed: 0B(0.00%) gzip: ▼-1B(0.00%) @mui/x-date-pickers-pro/MobileTimeRangePickerparsed: 0B(0.00%) gzip: ▼-1B(0.00%) @mui/x-date-pickers-pro/MultiInputDateRangeFieldparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/MultiInputDateTimeRangeFieldparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/MultiInputTimeRangeFieldparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/PickersRangeCalendarHeaderparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/SingleInputDateRangeFieldparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/SingleInputDateTimeRangeFieldparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/SingleInputTimeRangeFieldparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers-pro/StaticDateRangePickerparsed: 0B(0.00%) gzip: ▼-1B(0.00%) @mui/x-date-pickers-pro/TimeRangePickerparsed: 0B(0.00%) gzip: ▼-1B(0.00%) @mui/x-date-pickers/AdapterDateFnsparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/AdapterDateFnsBaseparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/AdapterDateFnsJalaliparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/AdapterDayjsparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/AdapterLuxonparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/AdapterMomentparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/AdapterMomentHijriparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/AdapterMomentJalaaliparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DateCalendarparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DateFieldparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DatePickerparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DateTimeFieldparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DateTimePickerparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DayCalendarSkeletonparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DesktopDatePickerparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DesktopDateTimePickerparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DesktopTimePickerparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/DigitalClockparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/LocalizationProviderparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/MobileDatePickerparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/MobileDateTimePickerparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/MobileTimePickerparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/MonthCalendarparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/MultiSectionDigitalClockparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/PickerDay2parsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/PickersActionBarparsed: 0B(0.00%) gzip: 0B(0.00%) @mui/x-date-pickers/PickersCalendarHeaderparsed: 0B(0.00%) gzip: 0B(0.00%)

Details of bundle changes

Generated by :no_entry_sign: dangerJS against b149f2ae3f9c917b02c38eeb4b0fe6c7baa8aceb

mui-bot avatar May 19 '25 14:05 mui-bot

CodSpeed Performance Report

Merging #17900 will degrade performances by 11.34%

Comparing alexfauquette:test-axis-highlight (b149f2a) with master (ed7604e)

Summary

❌ 1 regressions
✅ 9 untouched benchmarks

:warning: Please fix the performance issues or acknowledge them on CodSpeed.

Benchmarks breakdown

Benchmark BASE HEAD Change
ScatterChartPro with big data amount 393.6 ms 444 ms -11.34%

codspeed-hq[bot] avatar May 19 '25 14:05 codspeed-hq[bot]

I think I would rather have a more generic api, like onAxisHighlightChange and highlightedAxes, where the identifier actually includes the axis dimension as a part of it.

We could do it, if we restrict ourself to axes with a data attribute. Otherwise the devs will receive a bunch of update to ignore. Each time the pointe rmoves along the y-axis on a line chart, there is an update 🙈

alexfauquette avatar May 20 '25 18:05 alexfauquette

This pull request has conflicts, please resolve those before we can evaluate the pull request.

github-actions[bot] avatar May 23 '25 08:05 github-actions[bot]

Based on feedback, I went with the following DX

  • The highlightedAxis={{ direction, axisId, dataIndex}} which is less flexible but already cover 99% of the usecases. It make sure only axes the a data property can be hihlighted.
  • The callback is now onAxisInteraction({ direction, axisId, dataIndex}[]). It's also only taking care of axes with data attribute.

The callback is get an array, because I plan to use the same one for the tooltip control. And the tooltip is able to support multiple axes so we will need to get an access to all of them

alexfauquette avatar May 28 '25 12:05 alexfauquette

This pull request has conflicts, please resolve those before we can evaluate the pull request.

github-actions[bot] avatar Jun 10 '25 07:06 github-actions[bot]

This pull request has conflicts, please resolve those before we can evaluate the pull request.

github-actions[bot] avatar Jun 23 '25 14:06 github-actions[bot]

This pull request has conflicts, please resolve those before we can evaluate the pull request.

github-actions[bot] avatar Jun 27 '25 13:06 github-actions[bot]