nivo
nivo copied to clipboard
Responsive charts issue when using FlexBox or CSS grids
Reproducible demo here: https://codesandbox.io/s/lp16vvz6n7
As you can see, the top chart here (in the flex row) is not responsive.
Happy to help contribute if no one on the core team immediately knows. It might have something to do with react-measure that's used in @nivo/core
for the <ResponsiveWrapper>
component.
I solved this issue with the AutoSizer HOC.
import { AutoSizer } from 'react-virtualized'
<AutoSizer>
{({ height, width }) => (
<Pie
height={height}
width={width}
...
/>
)}
</AutoSizer>
Because of the known issues like "infinitely growing diagrams" I almost always use the AutoSizer wrapper in favour of the <Responsive*> components.
I ran into this issue too. I ended up using Recharts instead because I was on a deadline and I needed something that worked. It's unfortunate, because the Nivo charts certainly look better.
@ja0nz Wow this works great. I've been using React Virtualized for a while now but I never would have thought to use its auto-sizer. Thanks
I was having the same issue when using the <ResponsiveLine>
component inside a flex container. Strangely, when increasing the viewport width the chart would resize perfectly, but when decreasing it the chart would stay as it was as its widest point. Refreshing the page would fix everything again.
I've since implemented @ja0nz solution (as well as changing from <ResponsiveLine>
to <Line>
) and can confirm that it works a treat.
react-virtualized
is a great library but quite heavy.
There is a separate package for auto sizing called react-virtualized-auto-sizer
.
The following code is a light-weight version of @ja0nz's solution.
import AutoSizer from "react-virtualized-auto-sizer";
Minor addition to @ja0nz's solution. I think AutoSizer width should be 100% to keep the tooltips inbound.
import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer';
<AutoSizer style={{ width:'100%' }}>
{({ height, width }) => (
<Pie
height={height}
width={width}
...
/>
)}
</AutoSizer>```
Like @tanmaybhatt said, the tooltip (both anchor and tooltip width) has problems when using @ja0nz 's solution. To sum it up, the Autosizer container for the chart has 0 width, which causes the tooltip calculation to incorrectly detect a width of 0 all the time here https://github.com/plouc/nivo/blob/f2816f44f2fad60025d57bca6721c3c1cec8f14b/packages/tooltip/src/hooks.js#L35 which then decides to always use the same anchor direction.
My fix for it was something like this: (do take into account that my chart has a fixed height)
<AutoSizer disableHeight>
{({width}) => (
<div style={{width: width + 'px'}}>
<Line
height={500}
width={width}
//...
/>
</div>
</AutoSizer>
Reproducible demo here: https://codesandbox.io/s/lp16vvz6n7
Got similar problem and tried to tinker with your sandbox.
I solved this by adding min-width: 0
.flex-1 {
flex: 1 1 0%;
min-width: 0;
}
@ronsigter, like this:
<div style={{
minWidth: 0,
height: 400}}>
<WaffleChart data={data} />
</div>
?
Didn't work here
Any update on this bug? I am seeing the same behavior in both flexbox and grid. react-virtualized doesn't feel like a great work-around for me.
I tried to use Autosizer but then ~~any buttons~~ one below the chart component are unclickable. Any thoughts?
Edit: I know the problem now but not the solution. The <Autosizer>
component is in a <div>
with a button. The Parent <div>
height is 400px. The button is 20px. The <Autosizer>
assumes the parent's full height of 400 instead of 380 px. I'm not familiar with Autosizer, so is this the expected behavior?
I think I had a similar issue where my <ResponsiveBar>
would respond if zooming out but would not shrink when zooming in with my React app. The fix was to put the <ResponsiveBar>
into a <div>
that had a width
of less than 100%.
So the following fixed my problem:
<div style = {{width: "99%"}}>
<ResponsiveBar
...
/>
</div>
Not an ideal solution but setting the width
of the parent container to 100vw
worked. Had to use the calc
function to take into account padding and side nav, but it will do for now until Nivo release a fix.
also @TerryCLAWong's solution works perfectly too
Solution from @ronsigter worked for me 👍🏻
@ronsigter 's solution worked! I added it to container class.
Wasn't a big fan of the container class solution due to how my app is set up so I had to do the following on a Typescript React app where flexbox is used.
My pie chart component looks like this:
interface pieData {
id: string
label: string
value: number
color: string
}
interface pieProps {
data: pieData[]
minHeight?: number | string
minWidth?: number | string
}
export const DatavizSVGPie = ({
data,
minHeight = 0,
minWidth = 0
}: pieProps) => {
return (
<div
style={{
minHeight: minHeight,
minWidth: minWidth,
height: '100%',
width: '100%'
}}
>
<ResponsivePie
data={data}
...
/>
</div>
)
Then on the page where I'm using the component:
<div className="flex gap-6">
<div className="flex-1 flex flex-col items-center justify-center">
<DatavizSVGPie data={pieDataFormattedData} minHeight={292} />
</div>
</div>
minHeigth
and minWidth
are provided as variables to the component but default to 0
. This covers cases where you have a large legend that has to be accounted for such as the demo of programming languages provided on the main Nivo site.
This correctly inherited the height and width of the flexbox so it doesn't have to be set manually.
Hello, Is there any update concerning this issue. The workarounds proposed are working, however it's better to have a fix. Thank you in advance
Using the min-width: 0 worked for me too. Thanks.
I think I had a similar issue where my
<ResponsiveBar>
would respond if zooming out but would not shrink when zooming in with my React app. The fix was to put the<ResponsiveBar>
into a<div>
that had awidth
of less than 100%.So the following fixed my problem:
<div style = {{width: "99%"}}> <ResponsiveBar ... /> </div>
This was the correct solution for me too. I tried using minWidth but it didn't work.
I also noticed some strange behaviour too: If you set width: "99.9%"
and animate={false}
, you'll see a really slow animation of the graph shrinking to the correct size. With width: "99.5%"
the animation is there still, but much faster. At "99%" the animation roughly keeps up with me scaling the window so it's no longer that visible
This seems like a good solution so far:
<div
style={{
display: 'grid',
gridAutoColumns: 'minmax(0, 1fr)',
height: '24rem',
}}
>
<ResponsiveLine ... />
</div>
Note that, as shown, your container must have a height as well as the grid-auto-columns
value.
display: grid; grid-template-columns: repeat(2, 1fr); grid-auto-rows: minmax(0px, 1fr); height: 300px;
this is for the grid container, grid template columns depends on the number of grid items within the container.