react-smooth icon indicating copy to clipboard operation
react-smooth copied to clipboard

Causes chart to prematurely stop rendering

Open avindra opened this issue 4 years ago • 5 comments

There are some indications from users that Animations from react-smooth are causing the graph to render partially / in an incomplete state. Users have been using isAnimationActive={false} to disable animations to workaround the bug. See recharts issues:

https://github.com/recharts/recharts/issues/1426 https://github.com/recharts/recharts/issues/1821

avindra avatar Jan 14 '21 18:01 avindra

The issue seems to be related to the frequency in which your parent component needs to rerender, or possibly how often your data array reference changes. The workaround seems to be to do two things:

  • Force your chart to rerender when your parent component re-renders
  • Ensure your parent component does not rerender during the animation if possible. For me, I found that a parent component issue was causing my chart to rerender too often. That fix is not shown here.

I set a unique key on the Chart or ResponsiveContainer that forces the chart to rerender when the parent component rerenders. This can lead to issues with your chart reanimating on each rerender, which may not be your desired effect. Here is how I worked that out. Note that I'm turning off animations after a timeout to prevent duplicate animations after the key change. You would think that I could simply turn the animation off at onAnimationEnd but that callback seems to be called before the animation actually ends for some reason. It's also possible that your component will never actually finish the animation if this bug does happen to occur during the animation. I had better luck with the following approach:

const RingChart = ({data, colors, angle = 140}) => {
    let [animate, setAnimate] = useState(true)
    const onAnimationStart = useCallback(() => {
        setTimeout(() => {
            setAnimate(false)
        }, 2000)
    }, [])

    return (<div>
            <div  ref={ref} className={"absolute w-grid-7 h-grid-1 l-grid-7 t-grid-7"}/>
            <ResponsiveContainer key={uniqid()}>
                <PieChart>
                    <Pie
                        isAnimationActive={animate}
                        data={data}
                        startAngle={angle}
                        endAngle={angle + 360}
                        cx={'50%'}
                        cy={'50%'}
                        outerRadius={'70%'}
                        innerRadius={'47%'}
                        fill="#8884d8"
                        dataKey="value"
                        paddingAngle={0}
                        labelLine={<LabelLine/>}
                        label={<Label/>}
                        onAnimationStart={onAnimationStart}
                    >
                        {data.map((entry, index) => (
                            <Cell key={`cell-${index}`} fill={colors[index % colors.length]} stroke="none"/>
                        ))}
                    </Pie>
                </PieChart>
            </ResponsiveContainer>
        </div>
    )
}

incraigulous avatar Oct 14 '21 12:10 incraigulous

any updates ?

nightwolf-041 avatar Oct 31 '21 15:10 nightwolf-041

It's worth noting that when the Animate component unmounts, it does not call onAnimationEnd. This makes it impossible for recharts to clean up any outstanding animations when Animate unmounts.

Perhaps there could be an onAnimationStopped prop to address cases where the AnimateManager is stopped abruptly.

pl12133 avatar Dec 21 '21 19:12 pl12133

We would love a contribution from your side @pl12133 , calling the onAnimationEnd on unmount

semoal avatar Dec 22 '21 09:12 semoal

Merged https://github.com/recharts/react-smooth/pull/80 which calls onAnimationEnd on unmount - this should solve part of this

ckifer avatar Aug 29 '23 19:08 ckifer