Chart.js icon indicating copy to clipboard operation
Chart.js copied to clipboard

"responsive" option problem since v4

Open ghost opened this issue 3 years ago • 64 comments

Expected behavior

Chart should be resized when window size changes. (now it resizes only when scaling to smaller resolution)

Current behavior

I am using "responsive" option to resize chart based on it's parent container size. Everything works while scaling window size down, but when it comes to changing window resolution to larger one that doesn't work.

Reproducible sample

https://codepen.io/ouqu5/pen/ZEjEPqm

Optional extra steps/info to reproduce

  1. Resize window to mobile/tablet (chart resizes properly)
  2. Resize it back to full screen (chart is not resized)

Possible solution

No response

Context

No response

chart.js version

4.1.1

Browser name and version

No response

Link to your project

No response

ghost avatar Dec 20 '22 08:12 ghost

Hi ouqu5, have you tried to set the option maintainAspectRatio to false? And also, you will probably need to set the width and height in the parent container, not in the canvas element.

Read this docs about responsiveness: Responsive charts, read the important note about responsive charts and also check this example which is full responsive.

igomonteiro avatar Dec 21 '22 16:12 igomonteiro

I know that maintainAspectRatio fixes this problem but it should work event with this option enabled. I've followed all steps in docs so my chart setup is 100% valid.

Example you've send works because it's using chart.js 3.5.1 version while problem occurs only from version 4 of this library.

ouqu5 avatar Dec 22 '22 07:12 ouqu5

@ouqu5 the example also works with the latest version

igomonteiro avatar Dec 22 '22 13:12 igomonteiro

There is indeed an issue with version 4.x. When reducing size of container, it works. But not when increasing. Last working version 3.9.1.

legege avatar Dec 22 '22 19:12 legege

@igomonteiro example works only because of maintainAspectRatio: false. Try enabling it, as it is by default.

ouqu5 avatar Dec 23 '22 07:12 ouqu5

seeing this issue as well, with 4.1.1. in most cases. I would think this should work regardless of what maintainAspectRatio is set to.

jonbuda avatar Jan 04 '23 16:01 jonbuda

Any update on this? Still appears to be an issue in 4.2.0

JordanXA avatar Feb 07 '23 15:02 JordanXA

From my experience you have to define the height of the container, too, now. maintainAspectRatio respects container height.

ipax77 avatar Feb 07 '23 15:02 ipax77

By setting an aspect-ratio on the containing div I was able to get the same responsiveness for graphs using an aspect ratio. This confuses me because it seems like maintainAspectRatio should control the size of the canvas because if I wanted to size the container I would just size the container in the first place.

JordanXA avatar Feb 07 '23 17:02 JordanXA

Have this issue as well.

pavelspichonak avatar Feb 07 '23 18:02 pavelspichonak

I've had this issue as well—I have found a workaround, however. I'm using MUI specifically.

As long as the chart has a sibling that consumes space inside its parent, auto-resizing works. As soon as the chart sits alone in a parent, it will resize down but not up.

This does not work:

  return (
    <Box>
      <Chart
        type="bar"
        datasetIdKey="name" // the dataset property to use as the unique identifier for the data set. See: https://react-chartjs-2.js.org/docs/working-with-datasets/
        options={options}
        data={data}
        plugins={[legendExtraMargin]}
      />
    </Box>

This does not work:

  return (
    <Box>
      <div />
      <Chart
        type="bar"
        datasetIdKey="name" // the dataset property to use as the unique identifier for the data set. See: https://react-chartjs-2.js.org/docs/working-with-datasets/
        options={options}
        data={data}
        plugins={[legendExtraMargin]}
      />
    </Box>

This does work:

  return (
    <Box>
      <div>&nbsp;</div>
      <Chart
        type="bar"
        datasetIdKey="name" // the dataset property to use as the unique identifier for the data set. See: https://react-chartjs-2.js.org/docs/working-with-datasets/
        options={options}
        data={data}
        plugins={[legendExtraMargin]}
      />
    </Box>

YMMV but hopefully this workaround helps. Obviously, being forced to display something is not ideal, but you could adjust the size of the rendered element to mitigate. Interestingly, making it very small (max-height: 1px, font-size: 1px, or line-height: 0.1) causes the resize to animate very slowly ¯\(ツ)

ZLevine avatar Feb 16 '23 17:02 ZLevine

I was able to fix this without setting an exact container height by defining an aspect-ratio instead. The default aspect ratio for Chart.js is 2, so doing this restores Chart.js 3 behaviour:

<div class="chart-container" style="aspect-ratio: 2">
    <canvas id="chart"></canvas>
</div>

athisun avatar Mar 20 '23 06:03 athisun

I would suggest just to fix it instead of using workarounds. This is maybe not critical but important issue.

pavelspichonak avatar Mar 20 '23 18:03 pavelspichonak

Bumping this issue.

If I pass an onResize function to the options array of a chart component, like onResize: () => {console.log('Resizing chart')}, I am experiencing that the function fires when scaling the chart down, but it doesn't fire when the viewport scales up.

dan-ville avatar Apr 03 '23 14:04 dan-ville

I was able to fix this without setting an exact container height by defining an aspect-ratio instead. The default aspect ratio for Chart.js is 2, so doing this restores Chart.js 3 behaviour:

<div class="chart-container" style="aspect-ratio: 2">
    <canvas id="chart"></canvas>
</div>

@athisun 's workaround worked for me

Also onResize() is never being called for me with responsive: true...

On version 4.2.1

regnaio avatar Apr 11 '23 07:04 regnaio

I created a duplicate ticket for this issue (I didn't see this ticket prior to creating that one). I created a couple of Stackblitz demos to show the behavior working in 3.9.1 and not working in 4.3.0. I figured I'd cross-post them here:

Here's the 3.9.1 version, where responsiveness works: https://stackblitz.com/edit/angular-9rtbka

...And here's the 4.3.0 version, where responsiveness doesn't work (I also tried with 4.2.1, and got the same behavior): https://stackblitz.com/edit/angular-bcncvn

As noted above, responsiveness works when the browser width shrinks, but the chart doesn't expand as the browser width grows.

Hope this helps! Thanks!

hairbo avatar May 01 '23 14:05 hairbo

For me the event was only being triggered when my viewport increased in size, and the height property never seemed to update, only the width.

I was able to fix the issue with with this workaround:

canvas {
  width: 100% !important;
  height: 100% !important;
}

For what it's worth, I'm using Vue.js and including my charts with PrimeVue. The version of chart.js is v4.3.0.

If you're using this fix then the styles need adding globally.

t9luke avatar May 05 '23 09:05 t9luke

I'll throw my hat into this. I have the problem, I - for the life of mine - can not get it to shrink. At all. The example demo seems to work with all relative values, but when I do use percentages in my Angular (+ Tailwind) project, it does not.

<!-- This works! -->
<div class="chart-container w-[80vw] h-[300px]">
    <canvas #chart [id]="chartId" aria-label="Chart" role="img">
        <p>Chart could not be loaded</p>
    </canvas>
</div>

However...

<!-- This works! -->
<div class="chart-container w-[100%] h-[300px]">
    <canvas #chart [id]="chartId" aria-label="Chart" role="img">
        <p>Chart could not be loaded</p>
    </canvas>
</div>

Does not.

akleimrey avatar May 10 '23 11:05 akleimrey

I - for the life of mine - can not get it to shrink

@akleimrey This is likely since the new resize behaviour prioritizes maintaining the container height. Have you tried the above method of setting an aspect ratio instead of a height and width? https://github.com/chartjs/Chart.js/issues/11005#issuecomment-1475697112

athisun avatar May 10 '23 12:05 athisun

I - for the life of mine - can not get it to shrink

@akleimrey This is likely since the new resize behaviour prioritizes maintaining the container height. Have you tried the above method of setting an aspect ratio instead of a height and width? #11005 (comment)

@athisun I did but to no result. But in a perfect "Rubber Duck" problem-solving moment, I got a bit closer to my problem. My problem is the flexbox, but I can't simply replace my solution. It basically looks currently like this:

<div id="main" class="flex flex-col min-h-[100%] dark:bg-dark-background dark:text-background">
    <app-header></app-header>
    <div id="content" class="lg:w-[75rem] mx-auto">
        <router-outlet>
        </router-outlet>
    </div>
    <app-footer></app-footer>
</div>

And my dashboard page looks rather simple like that:

<app-map></app-map>
<app-chart [plugins]="plugin" chartType="HORIZONTAL_BAR"></app-chart>
<app-chart [plugins]="plugin2" chartType="BAR"></app-chart>

With a single chart component just looking like this:

<div class="chart-container w-[90%] h-[300px]">
    <canvas #chart [id]="chartId" aria-label="Chart" role="img">
        <p>Chart could not be loaded</p>
    </canvas>
</div>

So, the div with the id main is mostly used to at least occupy 100% space but is also used to always at the minimum have the footer at the bottom, without having to define positions. If the content is larger, the page grows nicely. I'm going through solutions to make this work, but apparently, there is no single simple solution ever.

akleimrey avatar May 10 '23 12:05 akleimrey

None of these are permanent solutions, though, right? We have a clear regression in behavior from 3.9 to 4.x when it comes to how responsive charts behave (in particular, when the browser increases in width). There are no indications in the documentation that this is a breaking change--if there were a documented best practice going forward (e.g., some kind of different CSS on the canvas or parent tag), then I think we could all happily upgrade. So until we hear otherwise, this just feels like a bug that needs to get addressed at the library level, rather than library consumers figuring out workarounds which may or may not work.

If I've missed something, and there really is documentation that this is a breaking change and we need to invoke our charts in a different fashion, I retract my above statement.

hairbo avatar May 10 '23 13:05 hairbo

For me the event was only being triggered when my viewport increased in size, and the height property never seemed to update, only the width.

I was able to fix the issue with with this workaround:

canvas {
  width: 100% !important;
  height: 100% !important;
}

For what it's worth, I'm using Vue.js and including my charts with PrimeVue. The version of chart.js is v4.3.0.

If you're using this fix then the styles need adding globally.

This worked for me using PrimeVue 3.25.0 and chart.js 4.3.0.

I am also observing the fact that the options.onResize function is only called when the container gets smaller; it doesn't fire when the container gets larger.

I am also observing the onResize function getting called occasionally in an infinite loop when the container gets smaller. I put a console.log in there and sometimes it logs 100s of times in a few seconds; it seems to catch itself if you continue resizing, but something occurs to make it decide to call onResize infinitely.

agm1984 avatar May 16 '23 19:05 agm1984

I have same behavior with css table-layout: fixed

https://angular-chart-js-nhvr2v.stackblitz.io

When the view grows, charts grow accordingly, when view goes smaller, chart size doesn't change correctly. When outside change is triggered, ie. do onblur from input, chart sizes are correct again. What's more, if I try the workaround of setting canvas size, the behavior changes to the opposite, increasing doesn't work and decreasing does.

I tried to replicate my use case as closely as possible, but it is kind of extreme behavior, so maybe this is not the best example for the problem, but leaving it here anyway in case it helps. It is very stable solution though in the environment I use it, the decreasing size is the only problem.

elinake avatar Jun 08 '23 12:06 elinake

I have the same problem. When responsive and maintaining aspect ratio the chart does not properly resize on expand. Collapsing works fine.

porteron avatar Jun 08 '23 18:06 porteron

When the view grows, charts grow accordingly, when view goes smaller, chart size doesn't change correctly.

🐛 Same issue. You have to reload the page after an enlargement to get the correct size of the chart again.

📖 I using [email protected], [email protected] and [email protected].

JulianWowra avatar Jun 21 '23 06:06 JulianWowra

Same issue. The chart scales down when page size reduces but does not properly expand when page size increases again. I have to reload the page to get back the correct size of the chart.

Example is shown here: https://www.teyanglau.com/ (on the nested radial chart)

teyang-lau avatar Jul 19 '23 00:07 teyang-lau

This still appears to be a problem in 4.4. Is there any word at all on the status of this issue? I don't think I've seen any of the library maintainers chime in on this thread.

hairbo avatar Aug 25 '23 14:08 hairbo

@etimberg Apologies for pinging you, but it would be great if you or one of the other maintainers could chime in on this issue. This seems like a clear regression from 3.9.x to 4.x.x, and it's preventing (at least) those of us on this thread from upgrading to 4.x of the library. I can't find anywhere in the docs that indicates this is a breaking change which involves some modification to how we invoke ChartJS for responsiveness.

Thanks!!

hairbo avatar Aug 28 '23 13:08 hairbo

Had the same issue, and for me this proposal solved it - https://github.com/chartjs/Chart.js/issues/11243 So one thing to do was to use aspect-ratio in chart container:

Using the aspect-ratio property it's possible to make a chart fit nicely within the parent container's width instead of the window size.

And what actually fixed the scaling issue when you resize the window to expand it - is to use overflow: hidden:

overflow: hidden is also needed otherwise the height won't change and won't trigger a redraw.

<div class="chart-container" style="position: relative; width: 100%; aspect-ratio: 2/1; overflow: hidden;">
    <canvas id="chart"></canvas>
</div>

That sounds like some sort of css issue, but still it should be addressed in some way by the Chart.js (as a fix, or in docs).

All credits goes to @PeterN !

sergei-krylov avatar Aug 29 '23 11:08 sergei-krylov

ChartJS also has an aspect ratio attribute. Do you need to set both in order for this to work? Also, do things work correctly if you change the aspect ratio after load?

bmueller-sykes avatar Aug 29 '23 11:08 bmueller-sykes