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] Add an overlay for "no data" or "loading" states #12817

Merged
merged 14 commits into from
Apr 29, 2024
76 changes: 76 additions & 0 deletions docs/data/charts/styling/CustomOverlay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import * as React from 'react';
import { styled } from '@mui/material/styles';
import Stack from '@mui/material/Stack';
import { BarChart } from '@mui/x-charts/BarChart';
import { useDrawingArea, useXScale, useYScale } from '@mui/x-charts/hooks';

const ratios = [0.2, 0.8, 0.6, 0.5];

const LoadingReact = styled('rect')({
opacity: 0.2,
fill: 'lightgray',
});

const LoadingText = styled('text')(({ theme }) => ({
stroke: 'none',
fill: theme.palette.text.primary,
shapeRendering: 'crispEdges',
Comment on lines +14 to +17
Copy link
Member

@oliviertassinari oliviertassinari May 5, 2024

Choose a reason for hiding this comment

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

We are missing the font here no?
SCR-20240505-sdjl

I would expect to see theme.typography.body1 or .body2 depending on what makes the most sense (maybe body2?)

textAnchor: 'middle',
dominantBaseline: 'middle',
}));

function LoadingOverlay() {
const xScale = useXScale();
const yScale = useYScale();
const { left, width, height } = useDrawingArea();

const bandWidth = xScale.bandwidth();

const [bottom, top] = yScale.range();

return (
<g>
{xScale.domain().map((item, index) => {
const ratio = ratios[index % ratios.length];
const barHeight = ratio * (bottom - top);

return (
<LoadingReact
x={xScale(item)}
width={bandWidth}
y={bottom - barHeight}
height={height}
/>
);
})}
<LoadingText x={left + width / 2} y={top + height / 2}>
Loading data ...
</LoadingText>
</g>
);
}

export default function CustomOverlay() {
return (
<Stack direction={{ md: 'row', xs: 'column' }} sx={{ width: '100%' }}>
<BarChart
slotProps={{
noDataOverlay: { message: 'No data to display in this chart' },
}}
series={[]}
margin={{ top: 10, right: 10, left: 25, bottom: 25 }}
height={150}
/>
<BarChart
loading
xAxis={[
{ scaleType: 'band', data: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] },
]}
slots={{ loadingOverlay: LoadingOverlay }}
series={[]}
margin={{ top: 10, right: 10, left: 25, bottom: 25 }}
height={150}
/>
</Stack>
);
}
76 changes: 76 additions & 0 deletions docs/data/charts/styling/CustomOverlay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import * as React from 'react';
import { styled } from '@mui/material/styles';
import Stack from '@mui/material/Stack';
import { BarChart } from '@mui/x-charts/BarChart';
import { useDrawingArea, useXScale, useYScale } from '@mui/x-charts/hooks';

const ratios = [0.2, 0.8, 0.6, 0.5];

const LoadingReact = styled('rect')({
opacity: 0.2,
fill: 'lightgray',
});

const LoadingText = styled('text')(({ theme }) => ({
stroke: 'none',
fill: theme.palette.text.primary,
shapeRendering: 'crispEdges',
textAnchor: 'middle',
dominantBaseline: 'middle',
}));

function LoadingOverlay() {
const xScale = useXScale<'band'>();
const yScale = useYScale();
const { left, width, height } = useDrawingArea();

const bandWidth = xScale.bandwidth();

const [bottom, top] = yScale.range();

return (
<g>
{xScale.domain().map((item, index) => {
const ratio = ratios[index % ratios.length];
const barHeight = ratio * (bottom - top);

return (
<LoadingReact
x={xScale(item)}
width={bandWidth}
y={bottom - barHeight}
height={height}
/>
);
})}
<LoadingText x={left + width / 2} y={top + height / 2}>
Loading data ...
</LoadingText>
</g>
);
}

export default function CustomOverlay() {
return (
<Stack direction={{ md: 'row', xs: 'column' }} sx={{ width: '100%' }}>
<BarChart
slotProps={{
noDataOverlay: { message: 'No data to display in this chart' },
}}
series={[]}
margin={{ top: 10, right: 10, left: 25, bottom: 25 }}
height={150}
/>
<BarChart
loading
xAxis={[
{ scaleType: 'band', data: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] },
]}
slots={{ loadingOverlay: LoadingOverlay }}
series={[]}
margin={{ top: 10, right: 10, left: 25, bottom: 25 }}
height={150}
/>
</Stack>
);
}
18 changes: 18 additions & 0 deletions docs/data/charts/styling/Overlay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as React from 'react';
import Stack from '@mui/material/Stack';
import { LineChart } from '@mui/x-charts/LineChart';

const emptySeries = {
series: [],
margin: { top: 10, right: 10, left: 25, bottom: 25 },
height: 150,
};

export default function Overlay() {
return (
<Stack direction={{ md: 'row', xs: 'column' }} sx={{ width: '100%' }}>
<LineChart loading {...emptySeries} />
<LineChart {...emptySeries} />
</Stack>
);
}
18 changes: 18 additions & 0 deletions docs/data/charts/styling/Overlay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as React from 'react';
import Stack from '@mui/material/Stack';
import { LineChart } from '@mui/x-charts/LineChart';

const emptySeries = {
series: [],
margin: { top: 10, right: 10, left: 25, bottom: 25 },
height: 150,
};

export default function Overlay() {
return (
<Stack direction={{ md: 'row', xs: 'column' }} sx={{ width: '100%' }}>
<LineChart loading {...emptySeries} />
<LineChart {...emptySeries} />
</Stack>
);
}
2 changes: 2 additions & 0 deletions docs/data/charts/styling/Overlay.tsx.preview
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<LineChart loading {...emptySeries} />
<LineChart {...emptySeries} />
38 changes: 38 additions & 0 deletions docs/data/charts/styling/OverlayWithAxis.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import * as React from 'react';
import Stack from '@mui/material/Stack';
import { LineChart } from '@mui/x-charts/LineChart';

const emptySeries = {
series: [],
margin: { top: 10, right: 10, left: 25, bottom: 25 },
height: 150,
};

export default function OverlayWithAxis() {
return (
<Stack direction={{ md: 'row', xs: 'column' }} sx={{ width: '100%' }}>
<LineChart
loading
xAxis={[{ data: [0, 1, 2, 4, 5] }]}
yAxis={[{ min: 0, max: 10 }]}
{...emptySeries}
/>
<LineChart
yAxis={[{ min: -5, max: 5 }]}
xAxis={[
{
scaleType: 'time',
data: [
new Date(2019, 0, 1),
new Date(2020, 0, 1),
new Date(2021, 0, 1),
new Date(2022, 0, 1),
],
tickNumber: 3,
},
]}
{...emptySeries}
/>
</Stack>
);
}
38 changes: 38 additions & 0 deletions docs/data/charts/styling/OverlayWithAxis.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import * as React from 'react';
import Stack from '@mui/material/Stack';
import { LineChart } from '@mui/x-charts/LineChart';

const emptySeries = {
series: [],
margin: { top: 10, right: 10, left: 25, bottom: 25 },
height: 150,
};

export default function OverlayWithAxis() {
return (
<Stack direction={{ md: 'row', xs: 'column' }} sx={{ width: '100%' }}>
<LineChart
loading
xAxis={[{ data: [0, 1, 2, 4, 5] }]}
yAxis={[{ min: 0, max: 10 }]}
{...emptySeries}
/>
<LineChart
yAxis={[{ min: -5, max: 5 }]}
xAxis={[
{
scaleType: 'time',
data: [
new Date(2019, 0, 1),
new Date(2020, 0, 1),
new Date(2021, 0, 1),
new Date(2022, 0, 1),
],
tickNumber: 3,
},
]}
{...emptySeries}
/>
</Stack>
);
}
34 changes: 34 additions & 0 deletions docs/data/charts/styling/styling.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,40 @@ This configuration can be used in Bar Charts to set colors according to string c
}
```

## Overlay

Charts have a _loading_ and _noData_ overlays that appears if

- `loading` prop is set to `true`.
- There is no data to display.

{{"demo": "Overlay.js"}}
JCQuintas marked this conversation as resolved.
Show resolved Hide resolved

### Axis display

You can provide the axes data in order to display them while loading the data.

{{"demo": "OverlayWithAxis.js"}}

### Custom overlay

To modify the overly message, you can use the `message` props as follow.

```jsx
<BarChart
slotProps={{
// Custom loading message
loadingOverlay: { message: 'Data should be available soon.' },
// Custom message for empty chart
noDataOverlay: { message: 'Select some data to display.' },
}}
/>
```

For more advanced customization, use the `loadingOverlay` and `noDataOverlay` slots link in the following demo.

{{"demo": "CustomOverlay.js"}}

## Styling

### Size
Expand Down
13 changes: 13 additions & 0 deletions docs/pages/x/api/charts/bar-chart.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"type": { "name": "union", "description": "object<br>&#124;&nbsp;string" },
"default": "yAxisIds[0] The id of the first provided axis"
},
"loading": { "type": { "name": "bool" } },
"margin": {
"type": {
"name": "shape",
Expand Down Expand Up @@ -152,6 +153,18 @@
"description": "Custom component for displaying tooltip content when triggered by item event.",
"default": "DefaultChartsItemTooltipContent",
"class": null
},
{
"name": "loadingOverlay",
"description": "Overlay component rendered when the chart is in a loading state.",
"default": "ChartsLoadingOverlay",
"class": null
},
{
"name": "noDataOverlay",
"description": "Overlay component rendered when the chart has no data to display.",
"default": "ChartsNoDataOverlay",
"class": null
}
],
"classes": [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
},
"required": true
},
"axisValue": { "type": { "name": "any" }, "required": true },
"classes": {
"type": { "name": "object" },
"required": true,
Expand All @@ -18,6 +17,9 @@
"type": { "name": "arrayOf", "description": "Array&lt;object&gt;" },
"required": true
},
"axisValue": {
"type": { "name": "union", "description": "Date<br>&#124;&nbsp;number<br>&#124;&nbsp;string" }
},
"dataIndex": { "type": { "name": "number" } }
},
"name": "DefaultChartsAxisTooltipContent",
Expand Down
13 changes: 13 additions & 0 deletions docs/pages/x/api/charts/line-chart.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"type": { "name": "union", "description": "object<br>&#124;&nbsp;string" },
"default": "yAxisIds[0] The id of the first provided axis"
},
"loading": { "type": { "name": "bool" } },
"margin": {
"type": {
"name": "shape",
Expand Down Expand Up @@ -155,6 +156,18 @@
"description": "Custom component for displaying tooltip content when triggered by item event.",
"default": "DefaultChartsItemTooltipContent",
"class": null
},
{
"name": "loadingOverlay",
"description": "Overlay component rendered when the chart is in a loading state.",
"default": "ChartsLoadingOverlay",
"class": null
},
{
"name": "noDataOverlay",
"description": "Overlay component rendered when the chart has no data to display.",
"default": "ChartsNoDataOverlay",
"class": null
}
],
"classes": [],
Expand Down
Loading
Loading