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

Responsive Chart #56

Closed
fizerkhan opened this issue Mar 26, 2013 · 75 comments
Closed

Responsive Chart #56

fizerkhan opened this issue Mar 26, 2013 · 75 comments

Comments

@fizerkhan
Copy link
Contributor

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?

@nnnick
Copy link
Member

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.

@fizerkhan
Copy link
Contributor Author

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

@stephanstapel
Copy link

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.

@nnnick
Copy link
Member

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.

@fizerkhan
Copy link
Contributor Author

@nnnick Thanks, it works now.

@decabyte
Copy link

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

@fizerkhan
Copy link
Contributor Author

@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;
}

@decabyte
Copy link

@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. :)

@fizerkhan
Copy link
Contributor Author

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

@fizerkhan
Copy link
Contributor Author

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
Copy link

sailing commented Apr 19, 2013

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

@psyose
Copy link

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
Copy link

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
Copy link

sailing commented Jun 18, 2013

@nezo's solution worked for me. :)

@andrewjmead
Copy link

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/

@VenuImmadi
Copy link

  • 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

@mkoistinen
Copy link

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...

@arifsetyawan
Copy link

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();

}

@thiagovidal
Copy link

@psyose function works like charm...

@andyadams
Copy link

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

@Pushplaybang
Copy link

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

@MikeAtWFU
Copy link

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.

@FvckSh1t
Copy link

oh my god, a great issue

@Kelimion
Copy link

Kelimion commented Dec 6, 2013

@arifLogic That worked a treat, thanks.

@ultrageek
Copy link

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).

@ultrageek
Copy link

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.

@dineshsdev
Copy link

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

@alejuu
Copy link

alejuu commented Feb 19, 2014

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

@fullstackto
Copy link

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);
};

@robrez
Copy link

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" ??

@RobbieTheWagner
Copy link

@jtblin does it work correctly for fixed height charts?

@RobbieTheWagner
Copy link

@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?

@jtblin
Copy link
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?

@RobbieTheWagner
Copy link

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

@RobbieTheWagner
Copy link

@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?

@jtblin
Copy link
Contributor

jtblin commented Jan 30, 2015

For labels, I don't think Chart.js allow that, see #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
Copy link

robrez commented Jan 30, 2015

Try "showScale: false"

@RobbieTheWagner
Copy link

@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.

@Saeven
Copy link

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
Copy link

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
Copy link

Muneem commented Jun 2, 2015

is there any way to adjust bars height?

@gnitnuj
Copy link

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;'

@adamscybot
Copy link

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.

@ghost
Copy link

ghost commented Jul 15, 2015

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
Copy link

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.

@cboehm-it
Copy link

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 .

@ghost
Copy link

ghost commented Jul 29, 2015

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;

@lowwa132
Copy link

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;
}

@josuejenkins
Copy link

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

@vatnoise
Copy link

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
Copy link

vatnoise commented Apr 27, 2016

^ 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.

@SimpleCookie
Copy link

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
Copy link

deep145 commented May 10, 2017

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);

@Venzon
Copy link

Venzon commented Dec 19, 2017

triggering resize event after rendering chart works for me

window.dispatchEvent(new Event('resize'));

@gmengi
Copy link

gmengi commented Apr 2, 2018

May I know how to decrease a thickness of DC chart?

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

No branches or pull requests