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.55k stars 1.33k forks source link

[charts] Pie chart overflow with legend #13648

Open ValberJunior opened 4 months ago

ValberJunior commented 4 months ago

Search keywords

responsiveChartContainer for PieChart

Related page

https://mui.com/x/react-charts/pie/

Kind of issue

Missing information

Issue description

I have a small problem with responsiveness when using Pie Charts. In the documentation there is a brief mention of the "RespomsiveChartContainer", but it doesn't show any example of use with Pie Chart, and I try to add it to my code and the Pie Chart doesn't render. On large screens, the subtitles are clearly visible, but when I reduce the screen,the subtitles are scrambled in the chart. Is there anything I can do to make it responsive without losing the subtitles?

Context

Current code:

import React from 'react'
import { ChartProps } from './types'
import { PieChart } from '@mui/x-charts/PieChart';
import { Box } from '@material-ui/core';

export const Chart : React.FC<ChartProps> = (props) => {

 const { items } = props;

  return (
      <Box sx={{ width:'100%'}}>
        <PieChart
        series={[
          {
            data: items,
            innerRadius: 50,
            highlightScope: { faded: 'global', highlighted: 'item' },
          }
        ]}
        height={250}
        slotProps={{
          legend: { 
              hidden: false
           },
        }}
      />
      </Box>
  );
}
alexfauquette commented 4 months ago

On large screens, the subtitles are clearly visible, but when I reduce the screen,the subtitles are scrambled in the chart.

You can use the margin={{ right: 150 }} (or other value, or top, left, bottom) to restrain the space available to draw the pie (end then free some space for the legend)

Here is an example, where you can modify right. https://codesandbox.io/p/sandbox/charming-blackburn-tl5yvr?file=%2Fsrc%2FDemo.tsx%3A11%2C12

At right: 50 it overflows. But at 150 it let enough space for the legend

image image

Does that solves your issue?

ValberJunior commented 4 months ago

Hello, how are you? So, maybe it will help a bit, but I ended up choosing to put the subtitles at the bottom and hide them when the screen is smaller:


import React from 'react'
import { ChartProps } from './types'
import { PieChart } from '@mui/x-charts/PieChart';
import { Box } from '@material-ui/core';

export const Chart : React.FC<ChartProps> = (props) => {

 const [ isHidden, setIsHidden ] = React.useState<boolean>(false);
 const { items } = props;
 const chartItems = (items.length === 1 && items[0].value === 0) ? [{id: items[0].id, label: items[0].label, value: 0.001}] : items;
 const size = {height: 450}

 const handleResize = () => {
  if(window && window.innerWidth < 950) setIsHidden(true);
  else setIsHidden(false);
 }

 React.useEffect(()=>{
  window.addEventListener('resize', handleResize);
  handleResize();

  return () => {
    window.removeEventListener('resize',handleResize)
  }
 },[])

  return (
    <Box sx={{ width: '100%', height: '100%' }}>
      <PieChart
        series={[
          {
            data: chartItems,
            innerRadius: '50%',
            highlightScope: { faded: 'global', highlighted: 'item' },
          },
        ]}
        slotProps={{
          legend: {
            hidden: isHidden,
            direction: 'row',
            position: { vertical: 'bottom', horizontal: 'middle' },
            padding: 0,
            labelStyle:{
              fontSize: 14
            },
            itemMarkWidth: 11,
            itemMarkHeight: 10,
          },
        }}
        margin={{ top: 100, bottom: 100, left: 100, right: 100 }}
        {...size}
      />
    </Box>
  );
}

In this case it helped, but I missed being able to manipulate the pieChart responsively, having control over its size and being able to edit the captions better. At first the idea was to have a personalized caption with a table, but as it was a bit obscure to manipulate the component, I opted to leave the caption below and create a separate explanatory table.

image

alexfauquette commented 4 months ago

At first the idea was to have a personalized caption with a table

The legend is currently in the SVG, so drawing a table might be complex. At that level of customization, the easiest might be to create your legend with HTML and display it next to the chart, and hide the legend

ValberJunior commented 4 months ago

Great, but how can I insert a new html into the chart? and even more, how can I get item by item, because I imagine that to draw an html table I would need to get the color of the item, the label and the value and iterate over the table. Are there any props that ChartPie accepts that I can do this with? Or any props that it exposes that I can manipulate?

alexfauquette commented 4 months ago

You don't need to put it in. You can put it out

function ChartsWithLegend() {
  <div>
    <PieChart />
    <MyLegend />
  </div>
}

how can I get item by item

You are providing the items to chat <PieChart/> so you have acce to them.

The only thing we defaultize is the color. Either you force them in the charts with <PieChart colors={[....]} />

or you can use the default one import { blueberryTwilightPalette } from '@mui/x-charts/colorPalettes';

blarson-hearst commented 1 week ago

Using margin "solves" the issue, but it is really only useful for static charts. Many of us have dynamic data, so the label height/width is unknown making overlaps very common. I've had to do clunky margin calculations based on legend character widths, but I have to overshoot it, so there often ends up being a lot of awkward white space.

I have investigated the source code too much, but the legend and the chart appear to be a single SVG. Without knowing much about the a11y impacts there, couldn't we split it into 2 SVGs and use something like flexbox to handle the flow so it can't overlap?

alexfauquette commented 1 week ago

The plan for the next major is to remove the current built-in legend and create a new one with HTML, so we can benefit from the Flex and other nice CSS text placement SVG miss.