mui / mui-x

MUI X: Build complex and data-rich applications using a growing list of advanced React components, like the Data Grid, Date and Time Pickers, Charts, and more!
https://mui.com/x/
4.08k stars 1.26k forks source link

Charts - Tooltip - custom item content #10352

Closed wascou closed 6 months ago

wascou commented 1 year ago

Duplicates

Latest version

Summary 💡

I would like to have documentation to know how to implement this.

Examples 🌈

There's no documentation at the moment or example in all the example pieces of code. Tooltip page is not mentionning it:https://mui.com/x/react-charts/tooltip/ It's specified in https://mui.com/x/api/charts/charts-tooltip/ as "itemContent". I've also tried to figure out how it works by coding an example.

<ScatterChart
     ...
      tooltip={{
        itemContent: (params: any) => {
          console.log(params)

          return null
        }
      }}
    />

Motivation 🔦

I would like to enrich the chart experience with a correct UI.

Order ID 💳 (optional)

No response

alexfauquette commented 12 months ago

In brief, to unlock you:

itemContent is passed here

And it expects a component that get following props: itemData={itemData} series={series} sx={sx} classes={classes}

itemData is an object that identify which item triggers the tooltip (type os the series, its id and if needed the index of the element in the series) series is the defaultized config of the triggered series

Not sure it's a "correct UI", but this codesandbox should help to understand how to use it

https://codesandbox.io/s/determined-dew-mkctjw?file=/Demo.tsx

wascou commented 11 months ago

Hey @alexfauquette

Thanks for this. I succeeded to use the itemContent component in my ScatterChart.

However, in my serie, I have object with a lot of attributes and in the CustomItemTooltipContent function passed to the trigger.ItemContent param, I can only have access to x, y and id parameters (ScatterValueType), not the all object attributes.

Do you know I can work around that?

alexfauquette commented 11 months ago

Sorry for the delay, I just saw I did not answer your last question.

The tooltip item content gets itemData and series. From that you can retrieve the entire object defining the scatter point

Here is an example with additional information

image

https://codesandbox.io/s/vibrant-violet-nj83jr?file=/Demo.tsx

const CustomItemTooltipContent = (props) => {
  const { itemData, series } = props;
  return (
    <Paper sx={{ padding: 3, backgroundColor: series.color }}>
      <p>{series.label}</p>
      <p>x: {series.data[itemData.dataIndex].x.toFixed(2)}</p>
      <p>y: {series.data[itemData.dataIndex].y.toFixed(2)}</p>
      <p>
        additional value: {series.data[itemData.dataIndex].other.toFixed(2)}
      </p>
      <p>
        other additional value:{" "}
        {series.data[itemData.dataIndex].other2.toFixed(2)}
      </p>
    </Paper>
  );
};
wascou commented 10 months ago

Thanks, working as espected. Two things on a side note:

  1. if used with ChartsTooltip, there's a deprecation on itemContent which moved to the slots prop.
  2. CustomItemToolTipContent is shown when the mouseover event is triggered (logic behavior)
alexfauquette commented 10 months ago

if used with ChartsTooltip, there's a deprecation on itemContent which moved to the slots prop.

Yes, I moved it to slots for coherence with the rest of the libraries

CustomItemToolTipContent is shown when the mouseover event is triggered (logic behavior)

You mean that you're manually triggering the mouseover event on scatter chart items?

wascou commented 10 months ago

I mean The tooltip code is triggered only if you put your mouse over the data point in the chart. If you have some rendering conditions in this part, it's run only on mouse over.

github-actions[bot] commented 6 months ago

:warning: This issue has been closed. If you have a similar problem, please open a new issue and provide details about your specific problem. If you can provide additional information related to this topic that could help future readers, please feel free to leave a comment.

How did we do @wascou? Your experience with our support team matters to us. If you have a moment, please share your thoughts through our brief survey.

jwitthaus commented 3 months ago

in either way (as tooltip and slot) I'm getting this error when using axisContent. It is only working for itemContent Cannot read properties of undefined (reading 'dataIndex') TypeError: Cannot read properties of undefined (reading 'dataIndex') at CustomItemTooltipContent (http://localhost:3000/tierpension/main.c140242e13170ec32343.hot-update.js:55:46) at renderWithHooks (http://localhost:3000/tierpension/static/js/bundle.js:105545:22) at mountIndeterminateComponent (http://localhost:3000/tierpension/static/js/bundle.js:109516:17) at beginWork (http://localhost:3000/tierpension/static/js/bundle.js:110819:20) at HTMLUnknownElement.callCallback (http://localhost:3000/tierpension/static/js/bundle.js:95801:18) at Object.invokeGuardedCallbackDev (http://localhost:3000/tierpension/static/js/bundle.js:95845:20) at invokeGuardedCallback (http://localhost:3000/tierpension/static/js/bundle.js:95902:35) at beginWork$1 (http://localhost:3000/tierpension/static/js/bundle.js:115800:11) at performUnitOfWork (http://localhost:3000/tierpension/static/js/bundle.js:115048:16) at workLoopSync (http://localhost:3000/tierpension/static/js/bundle.js:114971:9)

XpTo2k commented 2 months ago

@alexfauquette hi there! I trying to do this on a line chart but I'm having a problem reaching itemData.dataIndex

In the bar chart this value is available but not in line chart.

alexfauquette commented 1 month ago

Because the notion of item tooltip for the line chart is not well defined. I would not recommend using item tooltip for line chart

You could get a more advance customization example in #13944

If it does not solve your issue, please consider opening another one in which you explain what you try to achieve.

ThreeCrown commented 1 week ago

I am currently trying to manipulate the Tooltip for a BarChart. The problem seems to be that When I hover over both x axis groups, it displays all the data in the series instead of just the items I am wanting to display that are relevant to group. I was wanting to attempt to keep it as one chart rather than breaking it up into two charts.

    <BarChart
      dataset={data}
      xAxis={[{ scaleType: 'band', dataKey: 'group' }]}
      series={[
        { dataKey: 'unread', stack: 'unread', label: 'Unread' },
        { dataKey: 'confirmed', stack: 'confirmed', label: 'Confirmed' },
        { dataKey: 'completedOpen', stack: 'completed', label: 'Completed' },
        { dataKey: 'ignored', stack: 'ignored', label: 'Ignored' },
        { dataKey: 'total', stack: 'completedConfirmed', label: 'Total' },
        { dataKey: 'completed', stack: 'completedConfirmed', label: 'Completed' },
        { dataKey: 'assigned', stack: 'assigned', label: 'Assigned' },
        { dataKey: 'unassigned', stack: 'assigned', label: 'Unassigned' },
      ]}
      width={600}
      height={300}
      slotProps={{
        legend: { hidden: true },
      }}
      tooltip={{
        itemContent: CustomTooltipContent,
        trigger: 'axis',
      }}
    />
Data being passed:
```
  const data = [
{
  group: 'Open Bugs',
  unread: bugReportStatus.unread,
  confirmed: bugReportStatus.confirmed,
  ignored: bugReportStatus.ignored,
  completedOpen: bugReportStatus.completed,
  totalOpen:
    bugReportStatus.unread +
    bugReportStatus.confirmed +
    bugReportStatus.ignored +
    bugReportStatus.completed,
},
{
  group: 'Current Confirmed',
  total: bugReportStatus.confirmed,
  completed: bugReportStatus.completed,
  assigned:
    bugReportStatus.crownAssigned +
    bugReportStatus.snowAssigned +
    bugReportStatus.retroAssigned,
  unassigned:
    bugReportStatus.confirmed +
    bugReportStatus.completed -
    (bugReportStatus.crownAssigned +
      bugReportStatus.snowAssigned +
      bugReportStatus.retroAssigned),
},

];


 And I tried passing in a custom Tooltip:

const CustomTooltipContent: React.FC = (props) => { const { itemData, series } = props; const relevantDataKeys: Record<string, string[]> = { 'Open Bugs': ['unread', 'confirmed', 'ignored', 'completedOpen'], 'Current Confirmed': ['total', 'completed', 'assigned', 'unassigned'], }; const hoveredGroup = itemData.value; const keys = relevantDataKeys[hoveredGroup] || [];

return ( <Paper sx={{ p: '1em' }}>

Group: {hoveredGroup}

  {keys.map((key, idx) => {
    const seriesItem = series.find((s) => s.label === key);
    if (seriesItem) {
      return (
        <p key={idx}>
          {key}: {seriesItem.data[itemData.dataIndex]}
        </p>
      );
    }
    return null;
  })}
</Paper>

); };

alexfauquette commented 1 week ago

@ThreeCrown This issue is closed since a long time. Could you please open a new one with a codesandbox reproduction such that we can experiment with your issue.

This one should be a good starting point: https://codesandbox.io/p/sandbox/wqd5xt?file=%2Fsrc%2FDemo.tsx%3A6%2C14