Skip to content

Commit

Permalink
[charts] Fix area appearing (mui#14711)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexfauquette authored and Arthur Balduini committed Sep 30, 2024
1 parent 7394c6f commit d3853e3
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 60 deletions.
32 changes: 6 additions & 26 deletions packages/x-charts/src/LineChart/AnimatedArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import PropTypes from 'prop-types';
import { styled } from '@mui/material/styles';
import { animated, useTransition } from '@react-spring/web';
import { color as d3Color } from '@mui/x-charts-vendor/d3-color';
import { cleanId } from '../internals/cleanId';
import type { AreaElementOwnerState } from './AreaElement';
import { useChartId, useDrawingArea } from '../hooks';
import { useStringInterpolator } from '../internals/useStringInterpolator';
import { AppearingMask } from './AppearingMask';

export const AreaElementPath = styled(animated.path, {
name: 'MuiAreaElement',
Expand Down Expand Up @@ -45,20 +44,9 @@ export interface AnimatedAreaProps extends React.ComponentPropsWithoutRef<'path'
*/
function AnimatedArea(props: AnimatedAreaProps) {
const { d, skipAnimation, ownerState, ...other } = props;
const { left, top, right, bottom, width, height } = useDrawingArea();
const chartId = useChartId();

const stringInterpolator = useStringInterpolator(d);

const transitionAppear = useTransition([1], {
from: { animatedWidth: left },
to: { animatedWidth: width + left + right },
enter: { animatedWidth: width + left + right },
leave: { animatedWidth: left },
reset: false,
immediate: skipAnimation,
});

const transitionChange = useTransition([stringInterpolator], {
from: { value: 0 },
to: { value: 1 },
Expand All @@ -67,20 +55,12 @@ function AnimatedArea(props: AnimatedAreaProps) {
immediate: skipAnimation,
});

const clipId = cleanId(`${chartId}-${ownerState.id}-area-clip`);
return (
<React.Fragment>
<clipPath id={clipId}>
{transitionAppear((style) => (
<animated.rect x={0} y={0} width={style.animatedWidth} height={top + height + bottom} />
))}
</clipPath>
<g clipPath={`url(#${clipId})`}>
{transitionChange((style, interpolator) => (
<AreaElementPath {...other} ownerState={ownerState} d={style.value.to(interpolator)} />
))}
</g>
</React.Fragment>
<AppearingMask skipAnimation={skipAnimation} id={`${ownerState.id}-area-clip`}>
{transitionChange((style, interpolator) => (
<AreaElementPath {...other} ownerState={ownerState} d={style.value.to(interpolator)} />
))}
</AppearingMask>
);
}

Expand Down
40 changes: 6 additions & 34 deletions packages/x-charts/src/LineChart/AnimatedLine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ import PropTypes from 'prop-types';
import { animated, useTransition } from '@react-spring/web';
import { color as d3Color } from '@mui/x-charts-vendor/d3-color';
import { styled } from '@mui/material/styles';
import { cleanId } from '../internals/cleanId';
import type { LineElementOwnerState } from './LineElement';
import { useChartId } from '../hooks/useChartId';
import { useDrawingArea } from '../hooks/useDrawingArea';
import { useStringInterpolator } from '../internals/useStringInterpolator';
import { AppearingMask } from './AppearingMask';

export const LineElementPath = styled(animated.path, {
name: 'MuiLineElement',
Expand Down Expand Up @@ -48,22 +46,9 @@ export interface AnimatedLineProps extends React.ComponentPropsWithoutRef<'path'
*/
function AnimatedLine(props: AnimatedLineProps) {
const { d, skipAnimation, ownerState, ...other } = props;
const drawingArea = useDrawingArea();
const chartId = useChartId();

const stringInterpolator = useStringInterpolator(d);

const transitionAppear = useTransition<typeof drawingArea, { animatedWidth: number }>(
[drawingArea],
{
from: (v) => ({ animatedWidth: v.left }),
enter: (v) => ({ animatedWidth: v.width + v.left + v.right }),
leave: (v) => ({ animatedWidth: v.width + v.left + v.right }),
reset: false,
immediate: skipAnimation,
},
);

const transitionChange = useTransition([stringInterpolator], {
from: { value: 0 },
to: { value: 1 },
Expand All @@ -72,25 +57,12 @@ function AnimatedLine(props: AnimatedLineProps) {
immediate: skipAnimation,
});

const clipId = cleanId(`${chartId}-${ownerState.id}-line-clip`);
return (
<React.Fragment>
<clipPath id={clipId}>
{transitionAppear((style) => (
<animated.rect
x={0}
y={0}
width={style.animatedWidth}
height={drawingArea.top + drawingArea.height + drawingArea.bottom}
/>
))}
</clipPath>
<g clipPath={`url(#${clipId})`}>
{transitionChange((style, interpolator) => (
<LineElementPath {...other} ownerState={ownerState} d={style.value.to(interpolator)} />
))}
</g>
</React.Fragment>
<AppearingMask skipAnimation={skipAnimation} id={`${ownerState.id}-line-clip`}>
{transitionChange((style, interpolator) => (
<LineElementPath {...other} ownerState={ownerState} d={style.value.to(interpolator)} />
))}
</AppearingMask>
);
}

Expand Down
48 changes: 48 additions & 0 deletions packages/x-charts/src/LineChart/AppearingMask.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use client';
import * as React from 'react';
import { animated, useTransition } from '@react-spring/web';
import { cleanId } from '../internals/cleanId';
import { useChartId, useDrawingArea } from '../hooks';
import { SeriesId } from '../models/seriesType/common';

interface AppearingMaskProps {
id: SeriesId;
skipAnimation?: boolean;
children: React.ReactNode;
}

/**
* @ignore - internal component.
*/
export function AppearingMask(props: AppearingMaskProps) {
const drawingArea = useDrawingArea();
const chartId = useChartId();

const transitionAppear = useTransition<typeof drawingArea, { animatedWidth: number }>(
[drawingArea],
{
from: (v) => ({ animatedWidth: v.left }),
enter: (v) => ({ animatedWidth: v.width + v.left + v.right }),
leave: (v) => ({ animatedWidth: v.width + v.left + v.right }),
reset: false,
immediate: props.skipAnimation,
},
);

const clipId = cleanId(`${chartId}-${props.id}`);
return (
<React.Fragment>
<clipPath id={clipId}>
{transitionAppear((style) => (
<animated.rect
x={0}
y={0}
width={style.animatedWidth}
height={drawingArea.top + drawingArea.height + drawingArea.bottom}
/>
))}
</clipPath>
<g clipPath={`url(#${clipId})`}>{props.children}</g>
</React.Fragment>
);
}

0 comments on commit d3853e3

Please sign in to comment.