recharts icon indicating copy to clipboard operation
recharts copied to clipboard

Responsive Container it is very slow when resizing page

Open leorigon opened this issue 5 years ago • 38 comments

Do you want to request a feature or report a bug?

Seems like a bug.

What is the current behavior?

When I resize the page, the animation caused by ResponsiveContainer is very slow creating an horizontal overflow. This is propagated for all components in the page environment. I have a page with 4 charts like this:

  <ResponsiveContainer width='99%' minHeight={ 275 }>
        <BarChart
            { ...chartProps }
            data={ props.values }>
            <XAxis
                { ...axisProps }
                hide
            />
            <YAxis
                { ...axisProps }
                interval={ 0 }
                dataKey='date'
                type='category'
                tick={ {
                    ...chartTextProps,
                    fontSize: 10
                } }
            />
            <Tooltip
                separator={ '' }
                formatter={ formatLabelTooltip }
                labelFormatter={ formatDateTooltip }
            />
            <Bar
                dataKey='value'
                fill={ GREEN_LABEL }
                maxBarSize={ 12 }
                fontSize={ 10 } >
                <LabelList
                    dataKey='value'
                    position='right'
                />
            </Bar>
        </BarChart>
    </ResponsiveContainer>

What is the expected behavior?

Resize more fast or not too slow.

Which versions of Recharts, and which browser / OS are affected by this issue? Did this work in previous versions of Recharts?

Recharts "1.6.2": Ubuntu - Chrome 73.0.3683.103 (have same behaviour on all the OSs and browsers)

leorigon avatar Jun 07 '19 12:06 leorigon

I have the same problem. Please any feedback

stolaar avatar Jul 22 '19 13:07 stolaar

I do experience this, for what it's worth it only seems to be an issue when decreasing in size, increase in size works as expected.

benlester avatar Jul 30 '19 10:07 benlester

Same here

aksperiod avatar Aug 01 '19 21:08 aksperiod

I have the same issue. When I resize the window. all animation is very slow not smoothly. any idea to fix it :(((

ghost avatar Aug 24 '19 04:08 ghost

+1

chrisw90uk avatar Sep 03 '19 13:09 chrisw90uk

Also facing this. EDIT: I can always reproduce it if at the element containing the ResponsiveContainer shrinks due to another element growing in size (ex. one flex item in a single-row flex container changing width)

kalbert312 avatar Oct 30 '19 18:10 kalbert312

+1 I'm also experiencing the same issue. Appreciate if someone can help me.

BaldBit avatar Nov 07 '19 10:11 BaldBit

I made a code sandbox that sort of highlights it: https://codesandbox.io/s/gifted-elion-x3ilm?fontsize=14 It might just be a general performance problem if there's more than a few charts on the page. When the chart space grows, it is smooth. When it shrinks, it's not smooth unless there's only a couple charts. It happens even with a debounce value on the responsive containers. It would likely be noticeable on something like a dashboard.

kalbert312 avatar Nov 08 '19 18:11 kalbert312

+1

pchisholm avatar Dec 19 '19 16:12 pchisholm

Any updates? Is there a way to only disable resize animations but keep the others?

lukas1994 avatar Feb 03 '20 14:02 lukas1994

+1

cbaker avatar Feb 03 '20 20:02 cbaker

In my case, this was happening where there was a lot of data in the graphs. I'm representing the graphs in a flex box container, so I just added width: 0 property to the flex item and it solved the problem.

stolaar avatar Feb 04 '20 13:02 stolaar

@stolaar can you please elaborate a bit on your solution? Perhaps share your code? Much appreciated!

eli9000 avatar Feb 14 '20 03:02 eli9000

Sorry for my unclear solution above. So this was the solution in my case. I have the following graphs:

JSX:

<div className="dashboard>
   <div className="chart-container">
      <ResponsiveContainer width="99%" aspect={2}>
        {/* Graph components */ }
      </ResponsiveContainer>
    </div>
{  /* 5 more graphs here */ }
</div>

CSS:

.dashboard {
display: flex;
justify-content: space-evenly;
}

.chart-container {
flex: 0 1 500px;
width: 0;
}

width: 0 on the chart-container solves my problem.

stolaar avatar Feb 14 '20 11:02 stolaar

Having the same issue: trying to have a drawer component that forces the graphs to stretch and shrink. @stolaar's solution doesn't fix it for me.

m3h0w avatar Feb 19 '20 12:02 m3h0w

this happens because responsive container has width: 100%, and its child, that is svg element, has fixed width, equal to containers width in px. that means the containers actual width is equal to its child width. so when you resize down, container doesn't change dimensions, and resize observer callback never gets called.

my workaround is to position absolute ResponsiveContainer inside a 'responsive' div, and use that as a replacement.

import { ResponsiveContainer } from 'recharts';

function CustomResponsiveContainer(props) {
  return (
    <div style={{ width: '100%', height: '100%', position: 'relative' }}>
      <div
        style={{
          width: '100%',
          height: '100%',
          position: 'absolute',
          top: 0,
          left: 0
        }}
      >
        <ResponsiveContainer {...props} />
      </div>
    </div>
  );
}

VacaSan avatar Mar 13 '20 08:03 VacaSan

@VacaSan your fix made things slightly better but I'm still getting these laggy animations when resizing the window: https://share.getcloudapp.com/NQuD98GY

Any ideas on how to fix this? Is there a way to disable animations when resizing the window?

lukas1994 avatar May 17 '20 17:05 lukas1994

I had the same problem. I fixed it by adding "overflow-y: hidden;" to the ResponsiveContainer container.

My code is something similar to:

<div className="chart-wrapper">
  <p className="chart-title">
    Chart Title
  </p>
  <div className="recharts-container">
    <ResponsiveContainer>
      <AllOfRechartsCode />
    </ResponsiveContainer>
  </div>
</div>

With CSS:

.chart-wrapper {
  display: flex;
  flex-direction: column;
}

.recharts-container {
  flex-grow: 1;
  overflow-y: hidden;
}

I have a few similar components that use that same structure. Before I got to fix it, I had all of them with flex-wrap: wrap; instead of flex-direction: column; on .chart-wrapper. None of them had the overflow-y setting.

Then I changed flex-wrap to flex-direction, and just one of them started working properly. By comparing it to others, the only relevant difference was the overflow-y setting. So I just tested on the others components and they all worked.

I don't quite understand why that worked, though. Based on VacaSan's response, saying that observer callback never gets called on down resizing, I'd guess that for every resize step overflow would get recalculated or something, thus delaying a proper resize.

But I'm not even sure if that makes much sense. I'm not a very experienced developer, it was quite a struck of luck.

Anyways... Hope this helps.

felipe-perestrelo avatar Nov 03 '20 05:11 felipe-perestrelo

I see that this has been closed but I have yet to be able to remedy this issue in my app. I've tried every suggested css approach and nothing speeds up the size reduction animation. Where has this been conclusively resolved?

chuckponzi avatar Feb 13 '21 08:02 chuckponzi

I see that this has been closed but I have yet to be able to remedy this issue in my app. I've tried every suggested css approach and nothing speeds up the size reduction animation. Where has this been conclusively resolved?

I've encountered this issue maybe using debounce props on ResponsiveContainer will resolve the lag transition on the charts

carlocuevas avatar Aug 25 '21 02:08 carlocuevas

Hey all, I had been struggling with the same problem for ages. I used the '99%' width trick and it helped take maybe the edge off but with large data sets its still a very noticeable problem. I highly suggest using a hook similar to this one I made

import { useState, useEffect, useCallback } from 'react';
import lodash from 'lodash';
// A custom hook that detects if the window is currently being resized
// Returns a single value 'isBeingResized'
// the method is debounced to 200ms after which it returns to being false.

export const useIsResizing = () => {
  const [isBeingResized, setIsBeingResized] = useState(false);

  const reset = useCallback(
    lodash.debounce(() => {
      setIsBeingResized(false);
    }, 200),
    [],
  );

  useEffect(() => {
    const handleResize = () => {
      setIsBeingResized(true);
      reset();
    };

    window.addEventListener('resize', handleResize);

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

  return isBeingResized;
};

Then where ever you are rendering the graph simply remove it from the DOM while isBeingResized is true or show some placeholder text / component. This allows the layout to still resize in real time then the graph kind of pops back in when resizing ends.

Hope this helps someone!

dayyad avatar Nov 08 '21 02:11 dayyad

I see that this issue has been closed, even though it has not been fixed yet, and there are only workarounds stated. Currently in our application, I used AutoSizer instead of the responsive Container, but this should not be the solution for a highly used Framework like this, as its also not fixing the issue 100%

Zyntos avatar Jul 28 '22 12:07 Zyntos

Using flex-basis instead of width will help solve the problem

BeHustle avatar Jun 14 '23 15:06 BeHustle

Comments give me visibility into these closed issues, thanks. Reopening.

ckifer avatar Jun 14 '23 16:06 ckifer

I was suffering from similar issue and found that there's "debounce" props in ResponsiveContainer.

Try using the debounce props.

hywook4 avatar Aug 18 '23 04:08 hywook4

I'm not really proud of that solution but there it is haha, i'm pausing with a spinner to give the impression that it's not a bug and the resizing is as fast as usual. (DashboardBox is the component that wraps all the responsive containers i'm using)

I hope this helps.

import { Box } from "@mui/material";
import { styled } from "@mui/system";
import Spinner from "./Spinner";
import { useEffect, useState } from "react";

const DashboardBox = styled(Box)(({ theme }) => ({
  backgroundColor: theme.palette.background.light,
  borderRadius: "1rem",
  boxShadow: "0.15rem 0.2rem 0.15rem 0.1rem rgba(0, 0, 0, 0.8)",
}));

const ResizableBox = ({ children, gridArea }) => {
  const [isResizing, setIsResizing] = useState(false);

  let resizeTimeout;

  const handleResizeStart = () => {
    clearTimeout(resizeTimeout);
    setIsResizing(!isResizing);
  };

  const handleResizeEnd = () => {
    resizeTimeout = setTimeout(() => {
      setIsResizing(false);
    }, 150);
  };

  useEffect(() => {
    window.addEventListener("resize", handleResizeStart);
    window.addEventListener("resize", handleResizeEnd);

    return () => {
      window.removeEventListener("resize", handleResizeStart);
      window.removeEventListener("resize", handleResizeEnd);
    };
  }, []);

  return (
    <DashboardBox gridArea={gridArea}>
      {isResizing ? <Spinner /> : children}
    </DashboardBox>
  );
};

export default ResizableBox;

ablondel19 avatar Aug 19 '23 23:08 ablondel19

Hey everyone, so what's the ideal solution here? I've been trying to figure it out but no luck 🙏

mamo-muj avatar Oct 26 '23 13:10 mamo-muj

We've refactored responsive container for the next version which is directly using resize detector. The debounce prop is there and maybe next release we'll add a sane default

ckifer avatar Oct 26 '23 14:10 ckifer

@ckifer would you know what specific version has this update? I ask because I'm on version 2.0.6 and when I upgraded to 2.9.0, it throws me this error (something to do with the tsconfig.json)

So maybe if I update it to a specific version then hopefully I won't face this issue

image

mamo-muj avatar Oct 27 '23 06:10 mamo-muj

@mamo-muj can you create a separate issue for this? (please include webpack/bundler config, package.json, etc.) victory-vendor was added in 2.3 (but this issue we're in isn't fixed anywhere yet)

ckifer avatar Oct 27 '23 07:10 ckifer