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

Already on GitHub? Sign in to your account

Responsive Chart #56

Closed
fizerkhan opened this Issue Mar 26, 2013 · 73 comments

Comments

Projects
None yet
Contributor

fizerkhan commented Mar 26, 2013

Now, i have set width and height to the canvas element. But height and width of chart should be changed based on the Device.

I tried with bootstrap span element, it does not work. Any clues?

Owner

nnnick commented Mar 26, 2013

Set the width of the canvas using CSS. For retina devices Chart.js will apply a width inline, so your CSS might need an important.

Contributor

fizerkhan commented Mar 26, 2013

@nnnick I tried to set width and height with !important. But it does not work. The graph becomes stretched.

I can confirm the stretching effect.
Could you add a catch for the resize event and a consecutive redraw of the diagram?

@nnnick: if you could point me how to redraw the diagram, I could implement the handler.

Owner

nnnick commented Mar 26, 2013

Ok, I have a temporary solution now, and a better solution in the pipeline.

For now, in your CSS apply the following:

    canvas{
        width: 100% !important;
        max-width: 800px;
        height: auto !important;
    }

The max width (800px) is the width attribute on your canvas. This will at least scale properly as an image should, and you won't get into issues with stretching.

For the future, I'm looking at adding redraw events and a set of utility methods you'll be able to call once you've created your chart. For example:

var myChart = new Chart(ctx).Line(data,options);
myChart.reDraw();

Then, on your re-size events, you'll be able to reduce the size of your actual drawing canvas, and then call reDraw on your chart elements.

Contributor

fizerkhan commented Mar 27, 2013

@nnnick Thanks, it works now.

@nnnick the temporary solution doesn't work with Bootstrap fluid layout. BTW thanks for this awesome library! 👍

Contributor

fizerkhan commented Mar 28, 2013

@decabyte For me, It works with twitter bootstrap fluid layout. Here is the HTML and CSS

HTML

<div class="row-fluid">
        <div class="graph span6">
            <h3 class="title"> Pollution Vs Year</h3>
            <canvas id="barchart-canvas" height="300" width="550"></canvas>
        </div>
        <div class="graph span6">
            <h3 class="title">Supply Vs Demand</h3>
            <canvas id="linechart-canvas" height="300" width="550"></canvas>
        </div>
</div>

CSS

canvas {
            width: 100% !important;
            max-width: 800px;
            height: auto !important;
}

@fizerkhan yes, but this hack scales and stretches the canvas, which is rendered by the library at 550x300, making the text of the chart difficult to read if you are scaling to smaller viewport or pixelated if you are scaling up. :)

Contributor

fizerkhan commented Mar 28, 2013

@decabyte Yeah It is little bit stretched. Could not noticed previously.
May be i could check eye doctor. :)

Contributor

fizerkhan commented Mar 28, 2013

With this, little bit better for my graph.

        // upto landscape and desktop
        @media (max-width: 979px) {
            canvas {
                width: 100% !important;
                max-width: 800px;
                height: auto !important;
                // width: 500px !important;
                // height: 300px !important;
            }
        }

sailing commented Apr 19, 2013

+1 Any updates on fix for retina? Ability to redraw, or to use % instead of pixels?

psyose commented Apr 20, 2013

Got this solution to work without scaling and stretching the canvas.

HTML

<!--Place the canvas in a div and assign a class that has a width property defined.-->
<div class="span3">
  <canvas id="mycanvas"></canvas>
</div>

Coffee

setupCanvas = (canvas) ->
  canvas = $(canvas)
  # Set the size of the canvas to the parent div's size
  newWidth = canvas.parent().width()
  canvas.prop
    width: newWidth
    height: 200
  # Draw the chart
  ctx = canvas.get(0).getContext("2d")
  new Chart(ctx).Line mydata

((canvas) ->
  setupCanvas canvas
  # Listen for resize events (fires on mobile when you change orientation)
  $(window).resize ->
    setupCanvas canvas
) "#mycanvas"

+1 for a redraw method

nezo commented Jun 6, 2013

Hi all,
I had this issue lately, and I solved it by making my canvas width and height depends on the window.devicePixelRatio variable.

Which gives us the following code:

var pixelRatio = window.devicePixelRatio || 1;
var width = 404 / pixelRatio;
var height = 404 / pixelRatio;

I populate my canvas elements in javascript so this is easy for me using this way, but I guess you can fix it using media queries as well. (Have a look at these here.)

sailing commented Jun 18, 2013

@nezo's solution worked for me. :)

I am still running into this issue. I'm trying to get a fixed height, flexible width line chart. I have attached my fiddle. http://jsfiddle.net/andrewjmead/QNnZ6/

  • fizerkhan 👍 tanQ guy`s its is so helpful but also some issues with

canvas {
width: 100% !important;
max-width: 1000px;
height: auto !important;

}

for wide screens it does`nt look good like blur effect. i think it can be done by window.resize method in js..
blur

I'm having the best luck with this:

<!-- HTML -->
<canvas id=#blah width=500 height=300></canvas>


/* CSS */
#blah {
    width: 500px;
    height: 300px;
}

// JS
var $cvs = $('#blah');

if (window.devicePixelRatio != 1) {
    $cvs.removeAttr('width');
    $cvs.removeAttr('height');
}

var ctx = $cvs.get(0).getContext('2d');
...

Although, the text is super-sized on Retina devices, at least the canvas fits the layout... easy to fix, just divide the desired font-size by the devicePixelRatio...

i tried my best luck in modification here : https://github.com/arifLogic/respChartJS

function respChart(selector, data, options){

// Define default option for line chart
var option = {
    scaleOverlay : false,
    scaleOverride : false,
    scaleSteps : null,
    scaleStepWidth : null,
    scaleStartValue : null,
    scaleLineColor : "rgba(0,0,0,.1)",
    scaleLineWidth : 1,
    scaleShowLabels : true,
    scaleLabel : "<%=value%>",
    scaleFontFamily : "'proxima-nova'",
    scaleFontSize : 10,
    scaleFontStyle : "normal",
    scaleFontColor : "#909090", 
    scaleShowGridLines : true,
    scaleGridLineColor : "rgba(0,0,0,.05)",
    scaleGridLineWidth : 1, 
    bezierCurve : true,
    pointDot : true,
    pointDotRadius : 3,
    pointDotStrokeWidth : 1,
    datasetStroke : true,
    datasetStrokeWidth : 2,
    datasetFill : true,
    animation : true,
    animationSteps : 60,
    animationEasing : "easeOutQuart",
    onAnimationComplete : null
}

// check if the option is override to exact options 
// (bar, pie and other)
if (options == false || options == null){
    options = option;
} 

// get selector by context
var ctx = selector.get(0).getContext("2d");
// pointing parent container to make chart js inherit its width
var container = $(selector).parent();

// enable resizing matter
$(window).resize( generateChart );

// this function produce the responsive Chart JS
function generateChart(){
    // make chart width fit with its container
    var ww = selector.attr('width', $(container).width() );
    // Initiate new chart or Redraw
    new Chart(ctx).Line(data, options);
};

// run function - render chart at first load
generateChart();

}

@psyose function works like charm...

@psyose's solution also worked for me. Thanks, pal!

canvas element doesn't seem to scale the height correctly in IE with height auto - any ideas ? (charts land up stretched)

Yet another solution. Uses style sheet to stretch/shrink the chart and a delayed redraw event to clear things up after the user has finished resizing. The redraw keeps the chart in focus. The style sheet keeps the chart responsive and cuts down on the flicker while the user is actively resizing the window.

first add to CSS

canvas{
    width: 100% !important;
    min-width: 800px;
    height: 300px;
}

next add your redraw function and bind it to resize event

function resizeChart() {
    var canvas = document.getElementById("canvas");

    //set new sizes                 
    var new_canvasWidth = Math.max((canvas.parentNode.clientWidth), 800);
    var new_canvasHeight = 300;

    //only redraw if the size  has changed
    if ((new_canvasWidth != canvas.width) || (new_canvasHeight != canvas.height)) {
        canvas.width = new_canvasWidth;
        canvas.height = new_canvasHeight;
        new Chart(canvas.getContext("2d")).Line(lineChartData[data, options);
    }
}
//resizeTracker, clearTimeout, and setTimeout are used to only fire the resize event after the user has finished resizing; rather than firing lots of times unnecessarily while resizing.
var resizeTracker;
window.addEventListener('resize', (function(){clearTimeout(resizeTracker);resizeTracker = setTimeout(resizeChart, 100);}), false);

Note that my example uses a minimum width and fixed height. Should be easy to change that to suit your needs.

oh my god, a great issue

Kelimion commented Dec 6, 2013

@arifLogic That worked a treat, thanks.

I've used a combo of media queries, using a larger canvas size (e.g., 800x400) and editing a local copy of Chart.js to use a font size of 16 instead of 12. It's a hack, but it's the simplest that works (only tested in Chrome on Mac so far, but I've used media queries similar to that of Bootstrap).

Actually, here's a nice solution if you're using Bootstrap: http://stackoverflow.com/questions/17740901/bootstrap-grid-not-working-with-canvas. However, the height of the re-rendered chart was wonky. For my purposes, I used width()*0.5, in the JavaScript code.

Responsive chart example http://jsfiddle.net/LHMRJ/

alejuu commented Feb 19, 2014

@dineshgithub Im trying your solution, but it doesn't work with a radar chrat

Here is what we came up with for responsive canvas.

On entry we set the canvas to the width of the parent element which is a 100% width container, then draw the chart. We then repeat that when we resize the window.

var width = $('canvas').parent().width();
$('canvas').attr("width",width);
new Chart(ctx).Line(data,options);
window.onresize = function(event){
    var width = $('canvas').parent().width();
    $('canvas').attr("width",width);
    new Chart(ctx).Line(data,options);
};

@fullstackto Your solution works and is nice and concise

My x-axis is dates, but they are out of order for Chrome, but not Firefox. Has anyone else see this issue?

firefox
chrome

@fullstackto thanks, works for me and in bootstrap ! :)

mrkhyns commented May 22, 2014

@psyose Thanks - your solution worked perfectly for me.

@FVANCOP FVANCOP referenced this issue in FVANCOP/ChartNew.js May 29, 2014

Closed

How to fill up container? #43

@fullstackto perfect thanks!

Owner

nnnick commented Jul 4, 2014

New version will do this automatically by passing responsive:true into your options for the chart.

Doing that will automatically fill to its container size.

@nnnick nnnick closed this Jul 4, 2014

my solition is the simplest i think :)
jquery is required.

function draw(){

    var selector = '#area-chart';

    $(selector).attr( 'width', $(selector).parent().width() )
    myLine = new Chart(document.getElementById('area-chart').getContext('2d')).Line(lineChartData2);

}
$(window).resize( draw );
draw()

Why the hell do I always read through these big threads and try to come up with my own solution before skipping to bottom for the "this is fixed now" post? =[

Edit Actually, the responsive: true thing has no concern for fixed-height charts.

You go and try that lol it wouldn't reprint to be hi-res anyways the
creator already fixed this.

On Saturday, September 13, 2014, Eric Range notifications@github.com
wrote:

??? just add css:

width: inherit!important;
height: inherit!important;

done...


Reply to this email directly or view it on GitHub
nnnick#56 (comment).

flo-sch commented Nov 30, 2014

@emreakay What about :

var selector = '#area-chart',
    $canvas = $(selector),
    context = $canvas.get(0).getContext('2d');
$(window).on('resize', function (event) {
    $canvas.attr('width', $canvas.parent().width());
    myLine = new Chart(context).Line(lineChartData2);
}).trigger('resize');

yes it works, I have tested
I my case, I have a 'select' with list of locations. With each location data reloads in pie.
Issue ( Only when window is Zoomed Out) : With each reload the width and height of the canvas decreased continuously. Ultimately after 4 to 5 reloads the pie almost vanishes.
Solution: Before every reload, delete the previous canvas so that the older canvas along with its values is deleted.

Using responsive:true in the options is the way to go. @shivabhusal's solution reanimates the creation of the chart on resize.

hey @archonic , responsive:true is not the solution, irrespective of responsive:true the chart's size goes on decreasing for -ve zoom and increases for +ve zoom : Condition: The Window's zoom must not be 100%

@flo-schield-bobby thats good :)

I can't make this work. I tried this

.historyLinechart{
  height: auto !important;
  max-height: 100px;
  width:100% !important;
}

And I set responsive:true and I get a squished chart. Can anyone help me?
screen shot 2015-01-28 at 9 35 44 pm

Owner

etimberg commented Jan 29, 2015

@rwwagner90 are you continuously updating your chart by calling new? If so, you need to call destroy on the old chart first. Also, ensure that you are using the latest version since there was a fix for high DPI displays.

@etimberg I am not. I am using angles, an angular directive, so I don't have the actual chart object.

Owner

etimberg commented Jan 29, 2015

Hmm, I've never used Chart.js within Angular, however I quickly looked at the angles source. It looks like it is built on an old version. I'm not really familiar with angular enough to say with certainty, but I think it will re-create the chart when the data changes and autosize is set to true.

You could try changing lines 53 - 56 to

if (autosize) {
    $scope.size();

    if (chart)
    {
        chart.destroy();
    }

    chart = new Chart(ctx);
}
`
` 
Contributor

jtblin commented Jan 29, 2015

@etimberg is correct, angles and most chart.js angular directives destroy and re-create the chart on every data change. @rwwagner90 you should look at https://github.com/jtblin/angular-chart.js which does not do it (it updates when possible) and is responsive by default (disclaimer: I wrote it).

robrez commented Jan 29, 2015

@corysimmons mentioned on Jul 22, 2014 --

"Actually, the responsive: true thing has no concern for fixed-height charts."

I'm using "responsive: true", but I'd like to have a fixed height on the chart. Using "maintainAspectRatio: false" in combination with "max-height" in a style seems to work OK.

Is that approach "hacky" ??

@jtblin does it work correctly for fixed height charts?

@jtblin I tried your library, and it's still squished for a fixed height chart. Am I doing something wrong or is fixed height not supported?

Contributor

jtblin commented Jan 30, 2015

Fixed height is supported, someone reported an issue but without repro case, see jtblin/angular-chart.js#30 with a screenshot of a fixed height chart. Can you create a jsbin and open an issue in my repo and I will look into that?

Ahh, I was setting the height with css. Setting height in the html seems to work.

@jtblin is there a way to do a line chart without labels? I just want to plot points and not have to put in an empty string for each label. Also, I am setting colours to an array of colours and it just turns all black and white. What am I doing wrong?

Contributor

jtblin commented Jan 30, 2015

For labels, I don't think Chart.js allow that, see nnnick#12.

The line chart requires an array of labels for each of the data points. This is show on the X axis.

For colours see jtblin/angular-chart.js#42, unfortunately I need to do some work to allow setting colours via string. I will probably land that this weekend.

robrez commented Jan 30, 2015

Try "showScale: false"

@robrez that does allow you to hide the scale, but you still have to have a label for each point. I can just put a label for each one and hide it though, no big deal.

@aomran aomran referenced this issue in aomran/ember-cli-chart Feb 5, 2015

Closed

responsive chartjs #10

Saeven commented Mar 30, 2015

Nice lib. I had a similar issue, and finagled a fix this way, using Bootstrap. If I didn't do it this way, either the charts would progressively shrink, or they'd get blurry, or on hover the previous charts would appear.

<div class="canvas-container" style="height:160px;" data-chartjs="userSessionData">
        var repaint_timeout;

        function responsiveCharts() {
            if( repaint_timeout )
                clearTimeout( repaint_timeout );

            repaint_timeout = setTimeout( function()
            {
                $("div[data-chartjs]").each(function (s, t)
                {
                    var $div    = $(t);
                    $div.empty();

                    var $canvas = $("<canvas>");
                    $canvas.attr('height', $div.height() );
                    $canvas.attr('width', $div.width() );
                    $div.append( $canvas );

                    var ctx     = $canvas.get(0).getContext("2d");

                    new Chart(ctx).Line(chart_scope[$div.attr('data-chartjs')], {
                        reponsive: true,
                        maintainAspectRatio: false
                    });
                });
            }, 250 );
        }

Then in the body of the doc that drives my charts:

var chart_scope = {};
chart_scope.userSessionData = {
            labels: ["January", "February", "March", "April", "May", "June", "July"],
            datasets: [
                {
                    label: "My First dataset",
                    fillColor: "rgba(220,220,220,0.2)",
                    strokeColor: "rgba(220,220,220,1)",
                    pointColor: "rgba(220,220,220,1)",
                    pointStrokeColor: "#fff",
                    pointHighlightFill: "#fff",
                    pointHighlightStroke: "rgba(220,220,220,1)",
                    data: [65, 59, 80, 81, 56, 55, 40]
                },
                {
                    label: "My Second dataset",
                    fillColor: "rgba(151,187,205,0.2)",
                    strokeColor: "rgba(151,187,205,1)",
                    pointColor: "rgba(151,187,205,1)",
                    pointStrokeColor: "#fff",
                    pointHighlightFill: "#fff",
                    pointHighlightStroke: "rgba(151,187,205,1)",
                    data: [28, 48, 40, 19, 86, 27, 90]
                }
     ]
};


 $(document).ready( function(){

            $(window).resize(responsiveCharts);
            responsiveCharts();

 });

sgaawc commented Apr 23, 2015

I just wanna share my experience with the responsiveness behaviour for this lib.

I had to put 90 days (as short dates) in the (h) xAxis so because the 90 labels where all trying to fit into a one single axis it was impossible to be read and to know which data this axis points to.

The only workaround for that was a css fix:

Contain the canvas in two div parents;
the outer parent container set to:
.outerParent { position: relative; min-height: 10rem; overflow: hidden; overflow-x: scroll }
the inner parent container set to
.innerParent { position: absolute: top: 0; left: 0; width: 200rem; height: 200; max-height: 28rem; }

note: no width and height specific attributes for canvas tag!

// generate the chart

var toChart = new Chart( ctx ).Line( data, { maintainAspectRatio : !1 })

result:
the canvas is 200rem by width (very wide) and scrolls left/right (based on the page dir)
all horizontal axis labels are readable.

I hope it helps.

Muneem commented Jun 2, 2015

is there any way to adjust bars height?

gnitnuj commented Jun 12, 2015

My line chart kept increasing in height on window resize. Solved by setting setting static height on the canvas parent element: e.g. 'style="height: 400px !important;'

I was trying to create a fixed height responsive chart and was having various issues. Namely:

  • Getting bigger on every redraw.
  • Never shrinking

In the end, it was because I needed to both explicitly set the height of the canvas element, as well as setting the parent element to 100% width.

    .parent {
        width: 100%;
        canvas {
            height:340px !important;
        }
    }

I also use the maintainAspectRatio: false option but not sure if this has any effect.

Any actual fix to this? All the methods I have used fix the resizing but the chart is still affected, all the points and lines half in width same with the fonts and the hover states all change. Anyone managed to make it work as it should? Thanks for the awesome library though love the charts too much to change to another library but this is killing me, thanks!

akz92 commented Jul 17, 2015

I could only make it work adapting @nezo´s solution:

  var pixelRatio = window.devicePixelRatio || 1;
  var width = $('canvas').parent().width();
  var height = $('canvas').parent().height();
  ctx.canvas.width = width / pixelRatio;
  ctx.canvas.height = (1.5 * height) / pixelRatio;

  var myNewChart = new Chart(ctx).Line(data);

The vars width and height inherit its size from a parent div. After that I set it as the graph´s width and height. I multiplied height by 1.5 to make it look better in my layout, you may have to change that value or remove it.

I get good results with embedding the canvas into to div elements and changing the resize function little bit.

HTML

<div style="width:100%; height:400px">
    <div>
            <canvas id="myChart"></canvas>
    </div>
</div>

Changes in charts.js at extend(Chart.Type.prototype,{
Change

newHeight = this.options.maintainAspectRatio ? newWidth / this.chart.aspectRatio : getMaximumHeight(this.chart.canvas);

to

newHeight = this.options.maintainAspectRatio ? newWidth / this.chart.aspectRatio : canvas.height;

Does anybody know how I could override the resize() function within my javascript code? Currently I edited it directly in the chart.js .

I can confirm that @immertroll's solution nicely fixed the issue for me. I did not, however, have to make any edits to my HTML. I only needed to edit the line Chart.js. I'm using Bootstrap 3, so my markup looks something like this:

<div class="row">
    <div class="col-md-3">
        <canvas id="myChart"></canvas>
    </div>
    <div class="col-md-3">
        <p>blah blah blah</p>
    </div>
    <div class="col-md-3">
        <p>blah blah blah</p>
    </div>
    <div class="col-md-3">
        <p>blah blah blah</p>
    </div>
</div>

My overrides to the Chart.js defaults look like this:

Chart.defaults.global.responsive = true;
Chart.defaults.global.animation = false;
Chart.defaults.global.maintainAspectRatio = false;

A mix of @dougfelton and @immertroll solution:

<div class="row">
    <div class="col-md-9">
        <div>
            <canvas id="my-cavas"></canvas>
        </div>
    </div>
</div>

With:

Chart.defaults.global.responsive = true;
Chart.defaults.global.maintainAspectRatio = false;

And:

#my-canvas {
    height: 300px;
}

Just put the canvas in a container.
Then put a size in proportion to that container.
Then placed the chart options "responsive: true".

The chart will automatically adjust the size of the parent container.
Note: Do not place the size, or directly to the canvas, the size, or to position the parent container.

This worked for me:

CSS
#container{
width:100%;
}
HTML
<div id="container" >
<canvas> </canvas>
</div>
OPTIONS CHART

responsive:true

@dennissiemensma dennissiemensma referenced this issue in dennissiemensma/dsmr-reader Mar 13, 2016

Closed

Graphs keep increasing height on tablet #89

The problem for me is that my canvas container is width: 100% and so the first time page is loaded Chart.js finds the correct width but as soon as I start resizing the width only gets bigger, and I was thinking to get the parents width and use that for the canvas but apparently that's exacty what Chart.js is doing! So it seems that parent's size is changing when child's size is changing ...

vatnoise commented Apr 27, 2016 edited

^ I think I've got it working.

Firstly, I had the charts in a table and they were making the table bigger when resized, fixed that by adding style='table-layout: fixed;' to <table>.

Then added these options when creating new Chart:

responsive : true,
maintainAspectRatio: false,

Used @akz92 solution:

var pixelRatio = window.devicePixelRatio || 1;
var width = $(data['canvas']).parent().width();
var height = $(data['canvas']).parent().height();
data['ctx'].canvas.width = width / pixelRatio;
data['ctx'].canvas.height = (1.5 * height) / pixelRatio; 

Used @immertroll solution:
changed in Chart.js file:

newHeight = this.options.maintainAspectRatio ? newWidth / this.chart.aspectRatio : getMaximumHeight(this.chart.canvas);

to

newHeight = this.options.maintainAspectRatio ? newWidth / this.chart.aspectRatio : canvas.height;

And as the cake icing added width: 100%; height: 500px; to <table>.

So now all the charts are responsive with fixed height.

setTimeout solved the problem.

        setTimeout(function() {
            var ctx = elm[0].getContext('2d');
            var myBarChart = new Chart(ctx, {
                type: 'bar',
                data: $scope[attr.chartData],
                options: {
                    maintainAspectRatio: true,
                    responsive: true,
                    scales: {
                        xAxes: [{
                                stacked: false
                        }],
                        yAxes: [{
                                stacked: false
                        }]
                    }
                }
            });
        }, 100);

deep145 commented May 10, 2017 edited

chart js column width fixed issue please solved
var barData = {
labels: ['Italy', 'UK', 'USA', 'Germany', 'France', 'Japan'],
datasets: [
{
label: '2010 customers #',
fillColor: 'green',
data: [2500, 1902, 1041, 610, 1245, 952]
}

        ]
    };

    var context = document.getElementById('myChart').getContext('2d');
    var clientsChart = new Chart(context).Bar(barData);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment