Skip to content

Commit

Permalink
[charts] Add line animation (#11620)
Browse files Browse the repository at this point in the history
Signed-off-by: Alexandre Fauquette <[email protected]>
Co-authored-by: Lukas <[email protected]>
  • Loading branch information
alexfauquette and LukasTy authored Jan 30, 2024
1 parent dbd1809 commit 8392f53
Show file tree
Hide file tree
Showing 66 changed files with 1,048 additions and 387 deletions.
8 changes: 8 additions & 0 deletions docs/data/charts-component-api-pages.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import type { MuiPage } from '@mui/monorepo/docs/src/MuiPage';

const apiPages: MuiPage[] = [
{
pathname: '/x/api/charts/animated-area',
title: 'AnimatedArea',
},
{
pathname: '/x/api/charts/animated-line',
title: 'AnimatedLine',
},
{
pathname: '/x/api/charts/area-element',
title: 'AreaElement',
Expand Down
1 change: 1 addition & 0 deletions docs/data/charts/lines/ConnectNulls.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default function ConnectNulls() {
]}
height={200}
margin={{ top: 10, bottom: 20 }}
skipAnimation
/>
</Stack>
);
Expand Down
1 change: 1 addition & 0 deletions docs/data/charts/lines/ConnectNulls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default function ConnectNulls() {
]}
height={200}
margin={{ top: 10, bottom: 20 }}
skipAnimation
/>
</Stack>
);
Expand Down
1 change: 1 addition & 0 deletions docs/data/charts/lines/InterpolationDemoNoSnap.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export default function InterpolationDemoNoSnap() {
]}
height={300}
margin={{ top: 10, bottom: 30 }}
skipAnimation
/>
<HighlightedCode code={getExample(curveType)} language="tsx" />
</Box>
Expand Down
87 changes: 87 additions & 0 deletions docs/data/charts/lines/LineAnimation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import * as React from 'react';
import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import { LineChart } from '@mui/x-charts/LineChart';
import { mangoFusionPalette } from '@mui/x-charts/colorPalettes';

const defaultSeries = [
{ id: '1', data: [4, 5, 1, 2, 3, 3, 2], area: true, stack: '1' },
{ id: '2', data: [7, 4, 6, 7, 2, 3, 5], area: true, stack: '1' },
{ id: '3', data: [6, 4, 1, 2, 6, 3, 3], area: true, stack: '1' },
{ id: '4', data: [4, 7, 6, 1, 2, 7, 7], area: true, stack: '1' },
{ id: '5', data: [2, 2, 1, 7, 1, 5, 3], area: true, stack: '1' },
{ id: '6', data: [6, 6, 1, 6, 7, 1, 1], area: true, stack: '1' },
{ id: '7', data: [7, 6, 1, 6, 4, 4, 6], area: true, stack: '1' },
{ id: '8', data: [4, 3, 1, 6, 6, 3, 5], area: true, stack: '1' },
{ id: '9', data: [7, 6, 2, 7, 4, 2, 7], area: true, stack: '1' },
].map((item, index) => ({
...item,
color: mangoFusionPalette('light')[index],
}));

export default function LineAnimation() {
const [series, setSeries] = React.useState(defaultSeries);
const [nbSeries, setNbSeries] = React.useState(3);
const [skipAnimation, setSkipAnimation] = React.useState(false);

return (
<div
style={{
width: '100%',
display: 'flex',
flexDirection: 'column',
}}
>
<div>
<LineChart
xAxis={[{ data: [1, 2, 3, 4, 5, 6, 7] }]}
series={[
...series.slice(0, Math.min(nbSeries, 8)),
...series.slice(8, 10),
]}
skipAnimation={skipAnimation}
height={400}
/>
</div>
<Stack spacing={1} direction="row">
<Button
variant="outlined"
onClick={() =>
setSeries((prev) =>
prev.map((item) => ({
...item,
data: item.data.map((v) => Math.max(0.5, v - 4 + 8 * Math.random())),
})),
)
}
>
randomize
</Button>
<Button
variant="outlined"
onClick={() => setNbSeries((prev) => prev - 1)}
disabled={nbSeries === 0}
>
remove
</Button>
<Button
variant="outlined"
onClick={() => setNbSeries((prev) => prev + 1)}
disabled={nbSeries === 8}
>
add
</Button>
<FormControlLabel
checked={skipAnimation}
control={
<Checkbox onChange={(event) => setSkipAnimation(event.target.checked)} />
}
label="skipAnimation"
labelPlacement="end"
/>
</Stack>
</div>
);
}
87 changes: 87 additions & 0 deletions docs/data/charts/lines/LineAnimation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import * as React from 'react';
import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import { LineChart } from '@mui/x-charts/LineChart';
import { mangoFusionPalette } from '@mui/x-charts/colorPalettes';

const defaultSeries = [
{ id: '1', data: [4, 5, 1, 2, 3, 3, 2], area: true, stack: '1' },
{ id: '2', data: [7, 4, 6, 7, 2, 3, 5], area: true, stack: '1' },
{ id: '3', data: [6, 4, 1, 2, 6, 3, 3], area: true, stack: '1' },
{ id: '4', data: [4, 7, 6, 1, 2, 7, 7], area: true, stack: '1' },
{ id: '5', data: [2, 2, 1, 7, 1, 5, 3], area: true, stack: '1' },
{ id: '6', data: [6, 6, 1, 6, 7, 1, 1], area: true, stack: '1' },
{ id: '7', data: [7, 6, 1, 6, 4, 4, 6], area: true, stack: '1' },
{ id: '8', data: [4, 3, 1, 6, 6, 3, 5], area: true, stack: '1' },
{ id: '9', data: [7, 6, 2, 7, 4, 2, 7], area: true, stack: '1' },
].map((item, index) => ({
...item,
color: mangoFusionPalette('light')[index],
}));

export default function LineAnimation() {
const [series, setSeries] = React.useState(defaultSeries);
const [nbSeries, setNbSeries] = React.useState(3);
const [skipAnimation, setSkipAnimation] = React.useState(false);

return (
<div
style={{
width: '100%',
display: 'flex',
flexDirection: 'column',
}}
>
<div>
<LineChart
xAxis={[{ data: [1, 2, 3, 4, 5, 6, 7] }]}
series={[
...series.slice(0, Math.min(nbSeries, 8)),
...series.slice(8, 10),
]}
skipAnimation={skipAnimation}
height={400}
/>
</div>
<Stack spacing={1} direction="row">
<Button
variant="outlined"
onClick={() =>
setSeries((prev) =>
prev.map((item) => ({
...item,
data: item.data.map((v) => Math.max(0.5, v - 4 + 8 * Math.random())),
})),
)
}
>
randomize
</Button>
<Button
variant="outlined"
onClick={() => setNbSeries((prev) => prev - 1)}
disabled={nbSeries === 0}
>
remove
</Button>
<Button
variant="outlined"
onClick={() => setNbSeries((prev) => prev + 1)}
disabled={nbSeries === 8}
>
add
</Button>
<FormControlLabel
checked={skipAnimation}
control={
<Checkbox onChange={(event) => setSkipAnimation(event.target.checked)} />
}
label="skipAnimation"
labelPlacement="end"
/>
</Stack>
</div>
);
}
29 changes: 28 additions & 1 deletion docs/data/charts/lines/lines.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: React Line chart
productId: x-charts
components: LineChart, LineElement, LineHighlightElement, LineHighlightPlot, LinePlot, MarkElement, MarkPlot, AreaElement, AreaPlot
components: LineChart, LineElement, LineHighlightElement, LineHighlightPlot, LinePlot, MarkElement, MarkPlot, AreaElement, AreaPlot, AnimatedLine, AnimatedArea
---

# Charts - Lines
Expand Down Expand Up @@ -143,3 +143,30 @@ sx={{
```

{{"demo": "CSSCustomization.js"}}

## Animation

To skip animation at the creation and update of your chart, you can use the `skipAnimation` prop.
When set to `true` it skips animation powered by `@react-spring/web`.

Charts containers already use the `useReducedMotion` from `@react-spring/web` to skip animation [according to user preferences](https://react-spring.dev/docs/utilities/use-reduced-motion#why-is-it-important).

:::warning
If you support interactive ways to add or remove series from your chart, you have to provide the series' id.

Otherwise the chart will have no way to know if you are modifying, removing, or adding some series.
This will lead to strange behaviors.
:::

```jsx
// For a single component chart
<LineChart skipAnimation />

// For a composed chart
<ResponsiveChartContainer>
<LinePlot skipAnimation />
<AreaPlot skipAnimation />
</ResponsiveChartContainer>
```

{{"demo": "LineAnimation.js"}}
23 changes: 23 additions & 0 deletions docs/pages/x/api/charts/animated-area.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import * as React from 'react';
import ApiPage from 'docs/src/modules/components/ApiPage';
import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations';
import jsonPageContent from './animated-area.json';

export default function Page(props) {
const { descriptions, pageContent } = props;
return <ApiPage descriptions={descriptions} pageContent={pageContent} />;
}

Page.getInitialProps = () => {
const req = require.context(
'docsx/translations/api-docs/charts/animated-area',
false,
/\.\/animated-area.*.json$/,
);
const descriptions = mapApiPageTranslations(req);

return {
descriptions,
pageContent: jsonPageContent,
};
};
14 changes: 14 additions & 0 deletions docs/pages/x/api/charts/animated-area.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"props": { "skipAnimation": { "type": { "name": "bool" }, "default": "false" } },
"name": "AnimatedArea",
"imports": [
"import { AnimatedArea } from '@mui/x-charts/LineChart';",
"import { AnimatedArea } from '@mui/x-charts';"
],
"classes": [],
"muiName": "MuiAnimatedArea",
"filename": "/packages/x-charts/src/LineChart/AnimatedArea.tsx",
"inheritance": null,
"demos": "<ul><li><a href=\"/x/react-charts/lines/\">Charts - Lines</a></li></ul>",
"cssComponent": false
}
23 changes: 23 additions & 0 deletions docs/pages/x/api/charts/animated-line.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import * as React from 'react';
import ApiPage from 'docs/src/modules/components/ApiPage';
import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations';
import jsonPageContent from './animated-line.json';

export default function Page(props) {
const { descriptions, pageContent } = props;
return <ApiPage descriptions={descriptions} pageContent={pageContent} />;
}

Page.getInitialProps = () => {
const req = require.context(
'docsx/translations/api-docs/charts/animated-line',
false,
/\.\/animated-line.*.json$/,
);
const descriptions = mapApiPageTranslations(req);

return {
descriptions,
pageContent: jsonPageContent,
};
};
14 changes: 14 additions & 0 deletions docs/pages/x/api/charts/animated-line.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"props": { "skipAnimation": { "type": { "name": "bool" }, "default": "false" } },
"name": "AnimatedLine",
"imports": [
"import { AnimatedLine } from '@mui/x-charts/LineChart';",
"import { AnimatedLine } from '@mui/x-charts';"
],
"classes": [],
"muiName": "MuiAnimatedLine",
"filename": "/packages/x-charts/src/LineChart/AnimatedLine.tsx",
"inheritance": null,
"demos": "<ul><li><a href=\"/x/react-charts/lines/\">Charts - Lines</a></li></ul>",
"cssComponent": false
}
9 changes: 9 additions & 0 deletions docs/pages/x/api/charts/area-element.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"props": {
"skipAnimation": { "type": { "name": "bool" }, "default": "false" },
"slotProps": { "type": { "name": "object" }, "default": "{}" },
"slots": {
"type": { "name": "object" },
Expand All @@ -12,6 +13,14 @@
"import { AreaElement } from '@mui/x-charts/LineChart';",
"import { AreaElement } from '@mui/x-charts';"
],
"slots": [
{
"name": "area",
"description": "The component that renders the area.",
"default": "AnimatedArea",
"class": null
}
],
"classes": [
{
"key": "faded",
Expand Down
10 changes: 9 additions & 1 deletion docs/pages/x/api/charts/area-plot.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"props": {
"skipAnimation": { "type": { "name": "bool" }, "default": "false" },
"slotProps": { "type": { "name": "object" }, "default": "{}" },
"slots": {
"type": { "name": "object" },
Expand All @@ -12,7 +13,14 @@
"import { AreaPlot } from '@mui/x-charts/LineChart';",
"import { AreaPlot } from '@mui/x-charts';"
],
"slots": [{ "name": "area", "description": "", "class": null }],
"slots": [
{
"name": "area",
"description": "The component that renders the area.",
"default": "AnimatedArea",
"class": null
}
],
"classes": [],
"muiName": "MuiAreaPlot",
"filename": "/packages/x-charts/src/LineChart/AreaPlot.tsx",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"axisData": {
"type": {
"name": "shape",
"description": "{ x?: { index?: number, value: Date<br>&#124;&nbsp;number }, y?: { index?: number, value: Date<br>&#124;&nbsp;number } }"
"description": "{ x?: { index?: number, value: Date<br>&#124;&nbsp;number<br>&#124;&nbsp;string }, y?: { index?: number, value: Date<br>&#124;&nbsp;number<br>&#124;&nbsp;string } }"
},
"required": true
},
Expand Down
Loading

0 comments on commit 8392f53

Please sign in to comment.