Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chart increase size each redraw #84

Open
Oldwo1f opened this issue Mar 19, 2015 · 31 comments
Open

Chart increase size each redraw #84

Oldwo1f opened this issue Mar 19, 2015 · 31 comments

Comments

@Oldwo1f
Copy link

Oldwo1f commented Mar 19, 2015

Hi. I am facing the same issue as in 713 and 759 of Chart.js issues. But after a lot of testing, it appears not to be a Chart.js issue.

I give you a simple test case that reproduce the error.

<script src="/bower_components/jquery/dist/jquery.min.js"></script>
<script src="/bower_components/angular/angular.min.js"></script>
<script src="/bower_components/Chart.js/Chart.js"></script>
<script src="/bower_components/angular-chart.js/dist/angular-chart.js"></script>

<body ng-app="app" ng-controller="LineCtrl">
<h1>TEST</h1>
<div style="width:600px;height:400px; margin:50px auto;position:relative;">
<canvas id="line" class="chart chart-line" options="myoptions" data="data" height="300px" labels="labels" 
    legend="true" series="series" click="onClick"></canvas> 
</div>

<a class="toto" href="#" >click to change data</a>
<script type="text/javascript">

angular.module("app", ["chart.js"]).controller("LineCtrl", ['$scope', '$timeout', function ($scope, $timeout) {

  $scope.labels = ["January", "February", "March", "April", "May", "June", "July"];
  $scope.series = ['Series A', 'Series B'];
  $scope.myoptions = {scaleBeginAtZero : true,maintainAspectRatio: false,scaleShowGridLines : false}
  $scope.data = [
    [65, 59, 80, 81, 56, 55, 40],
    [28, 48, 40, 19, 86, 27, 90]
  ];
  $scope.onClick = function (points, evt) {
    console.log(points, evt);
  };

  // Simulate async data update
  $('.toto').click(function () {
    console.log('clicked');
    $scope.data = [
      [90, 48, 40, 19, 86, 27, 90],
      [65, 59, 80, 81, 56, 55, 40]
    ];
    $scope.$apply();
  });
}]);

</script>
</body>

you ll have to install dependencies
-----> bower install jquery angular Chart.js angular-chart.js

Can you please see whats happens when graph redraw.( on window resize or on data change i got the same problem)

@boonkerz
Copy link

Same Issue here

@jtblin
Copy link
Owner

jtblin commented Mar 26, 2015

I am not able to repro with pasting your code in jsbin (actually nothing show up). Can you create a valid repro with this jsbin template please?

@boonkerz
Copy link

with responsive=false it works

@JeroenJK
Copy link

@boonkerz You're right, with responsive=false it won't redraw itself bigger everytime, but what if you WANT responsive? On your phone for example, if you open it in portrait view, and then rotate the phone to landscape view, the chart is not sharp anymore. Blurry.

I asked a detailed question about this: http://stackoverflow.com/questions/29819173/strange-angular-chartjs-issue-not-displaying-correctly-in-ionic-app but there are not a lot of answers yet.

Also, when the chart is initially in an ng-hidden element, it's height will be 0.

I hope someone can solve this?

@luccascorrea
Copy link

I am having the same problem.

@ysoffner
Copy link

Same Issue

@jtblin
Copy link
Owner

jtblin commented May 28, 2015

Can you provide a jsbin to repro the issue instead of saying "me too"?

@jirihelmich
Copy link

I'm not really able to reproduce it on jsbin, I don't know what causes the problem. But here is the setup I have: https://jsfiddle.net/1t0x6qmb/

I would start with the fact that if I set height to 50, the actual height set to canvas via style is about 120px, if I set 150, the actual size is about 360px.

If I then use more data (read I have more items on x axis), the chart seems to double its height. Maybe it holds the ratio and as it grows wider (as its parent element does), it grows also in height?

@alanblake
Copy link

responsive= false also fixed my ever increasing chart height but I'm struggling now to get the dimensions the way I want. What is the correct way to specify the dimensions for a chart?

@jtblin
Copy link
Owner

jtblin commented Aug 22, 2015

Using width and height.
Can you provide a jsbin to repro?

@alanblake
Copy link

I resolved my issue by setting the canvas height in an external css file rather than inline in the canvas element. Setting height inline would increase by 5px every time the chart was created.

@jirihelmich
Copy link

            chartJsProvider.setOptions({
                responsive: true,
                maintainAspectRatio: false
            });

was what I needed.

@soyto
Copy link

soyto commented Sep 9, 2015

I have same issue, you can take a look on http://soyto.github.io/#/ranking/Alquima for example. When you resize the window you will how chart have their height increased.

If needed you can access sources on https://github.com/soyto/soyto.github.io

@farrago
Copy link

farrago commented Oct 20, 2015

I was also having problems getting the chart to fill the height properly, particularly with relative heights (% or vh based) and chart-legend enabled. I thought it might be worth sharing what I found to get proper height-filling results in those cases.

Why does it not work with the defaults?

  1. [chart.js] If maintainAspectRatio is true (the default), the height is essentially width x aspectRatio - i.e. it won't fill the height and will either overflow or be too small depending on your parent element.
  2. [chart.js] If responsive is false (the default), the chart won't resize as the page does. So it again won't track the height as the page height changes.
  3. [chart.js] Resizes the canvas to completely fill the height of the parent div (if maintainAspectRatio is false).
  4. [angular-chart.js] Angular-chart injects a chart-container div, with no styling by default, importantly including no css height, so it is inherited from the parent.
  5. [angular-chart.js] If chart-legend="true" angular-chart injects a chart-legend element for the legend below the chart, which obviously has a non-zero height.
  6. [Both] Items 3 + 4 + 5 = a chart where the legend overflows the height of the parent element (3 fills it, then 5 overflows it)
  7. [Both] Items 3 + 4 + 5 = a chart that keeps growing on every resize (if response is true). Item 5 increases the size of the parent div every time, then on refresh, item 3 fills the new bigger size, then item 5 injects the legend again, etc...

How to fix:

  1. Set maintainAspectRatio to false. Fixes point 1.
  2. Set responsive to true. Fixes point 2
  3. Set css height on parent element to be the overall relative height you want (e.g. 30vh).
  4. Set css height on .chart-container to be a calculated as parentHeight - legendHeight[1]. This reduces the height that chart files (point 3), and leaves space for the legend below (fixing points 6 & 7).

Hope this helps, and please do correct any mistakes in my explanation.

[1] E.g. something like height: calc(30vh - 2.85rem - 5px) seems to work ok (where 30vh is the parent height relative to the viewport, 2.85rem is the line height of the ul in Foundation, and 5px is the default margin-top from angular-chart.css. Note: calc() seems to have similar browser support to canvas so shouldn't be an issue using it here.

@Chuckv01
Copy link

@farrago THANK YOU SO MUCH! I have been fighting this issue for months now. Your solution finally allows me to have the graphs use the full height available on different devices. Kudos kudos kudos to you.

@Dashue
Copy link

Dashue commented Oct 26, 2015

I'm trying to put charts in a bootstrap col-lg-{{size} where size can be toggled through a select by the user.
Should @farrago solution be working in this case?

@tulga-orosoo
Copy link

Thank you @jirihelmich

@benramadan
Copy link

@farrago This has made me very happy. First rate debugging! Thank you.

@jtblin jtblin added the v0.x label Apr 15, 2016
@lrossy
Copy link

lrossy commented May 13, 2016

@farrago thanks for that detailed post. Helped me figure out my issue

@dangji
Copy link

dangji commented May 19, 2016

@farrago does not work on firefox

@Jiia
Copy link

Jiia commented Oct 7, 2016

@farrago's answer doesn't work anymore as Chart.js 2 uses canvas.

@djleonskennedy
Copy link

What about ChartJs 2.0 ?

@jtblin
Copy link
Owner

jtblin commented Oct 25, 2016

Chart.js 1.x was also using canvas so not sure this is relevant.

On Tue, Oct 25, 2016 at 7:32 PM, Yuriy notifications@github.com wrote:

What about ChartJs 2.0 ?


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#84 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABUxrmTrGEdly_RDadMM0ChzJqdz4mMkks5q3b66gaJpZM4DxDgN
.

@FrancescoCarraro
Copy link

FrancescoCarraro commented Jul 28, 2017

@farrago thanks for your solution. In my case the item 4 has been not needed to fix the issue.

@shivabhusal
Copy link

A hack

$('.chartjs-hidden-iframe').remove();
$('#chartjs-canvas').remove();
$('.chart').html('<canvas id="chartjs-canvas" height="300"></div>');
var myLine = new Chart($('#chartjs-canvas')[0].getContext("2d"), {

@jcg31
Copy link

jcg31 commented Oct 1, 2017

Multiple instances of iframes seem to be the issue. With each redraw chart.js is adding an iframe instance with the class "chartjs-hidden-iframe" to the DOM. Similar to shivabhusal above, with each redraw I am clearing those out.

I put the canvas inside a div, then with each redraw empty it, then appended the canvas back in.
$('#canvasdiv').empty;
$('#canvasdiv').append('<canvas id="mycanvas"></canvas')

@edin0x
Copy link

edin0x commented Dec 17, 2017

I solved this in a different way and would like to share my solution. So I wanted to keep it responsive, and solved it by setting the maintainAspectRatio on true for first render, and on false for each consequent rerender.

Example:

<script>
  import { Bar } from 'vue-chartjs';

  export default {
    extends: Bar,
    name: "bar-chart",
    props: ['chartData'],
    data() {
      return {
        renderData: {
          labels: this.chartData.map(d => d.label),
          datasets: [
            {
              backgroundColor: 'steelblue',
              data: this.chartData.map(d => d.value),
            },
          ]
        },
        renderOptions: {
          responsive: true,
          maintainAspectRatio: false,
          scales: {
            xAxes: [{
              barPercentage: 1.5
            }]
          },
          legend: {
            display: false,
          }
        }
      }
    },
    mounted() {
      this.renderChart(this.renderData, this.renderOptions);
    },
    watch: {
      chartData() {
        this.renderOptions.maintainAspectRatio = true;
        this.renderChart(this.renderData, this.renderOptions);
      }
    }
  }
</script>

This is the least hacky solution that I was able to find.

@jasonarg
Copy link

I ran into this same problem using vue.js to control updating a chart.js Chart instance. I found this page by doing some googling. A lot of these solutions helped me look in the right direction, thank you all.

However, the real problem for me ( and I suspect many others) turned out to be that I was recreating a whole new chart.js Chart object on data updates and attaching it to the same DOM (or VDOM) element as before, and NOT updating the already made chart.js Chart object using the chart.js Chart object's update method.

Once I used that, I had no doubling of height on each update and I didn't need to fiddle around with any responsive or maintainAspectRatio properties of the chart.js config.

Lesson learned, use Chart.update() on an existing Chart(), even if you stored no reference to the original.

Update documentation:
http://www.chartjs.org/docs/latest/developers/updates.html

My code:

Original Chart Instantiation code

 for(let i in this.scdbData.routeData.charts){
           new Chart(document.getElementById(i).getContext("2d"), 
                   this.scdbData.routeData.charts[i].config);
        }

The above code would be called after each time the data was updated.

Updated Chart Instantiation code

        for(let i in this.scdbData.routeData.charts) {
            if (this.scdbData.charts[i]) {
                this.scdbData.charts[i].data.labels = this.scdbData.routeData.charts[i].labels;
                this.scdbData.charts[i].data.datasets = this.scdbData.routeData.charts[i].datasets;
                this.scdbData.charts[i].update();
            }
            else {
                this.scdbData.charts[i] = new Chart(document.getElementById(i).getContext("2d"), 
                      this.scdbData.routeData.charts[i].config);
            }
        }

Now I store a reference to a Chart when created and I check to see if that reference exists. If it does, I update the properties of labels and datasets on the referenced chart and then call update().

jasonarg added a commit to jasonarg/saassycloud that referenced this issue Dec 29, 2017
* Recreating a new chart.js Chart object on every update and attaching it to a DOM element(or VDOM in this case) causes the chart's height to double in size.
* Similar to this issue jtblin/angular-chart.js#84 for an angular.js chart.js library
* Now storing a reference to each Chart created and calling native chart.js update methods on them when the data is refreshed.
  * http://www.chartjs.org/docs/latest/developers/updates.html
@gabrielpramos
Copy link

I don't know if it's some kind of help, but I had the same problem using the following options:
options: {
maintainAspectRatio: false,
responsive: true,
legend: {
position: 'bottom'
},
}

and worked when I modified to:

options: {
maintainAspectRatio: true,
responsive: true,
legend: {
position: 'bottom'
},
}

@Seabizkit
Copy link

mine was that i was inserting the containing div again i forgot the check to see if exists

@mdadil09
Copy link

Just change the responsive to true it will adjust automatically

responsive = true;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests