highcharts and canvg scaling issue

Jamie Poitra picture Jamie Poitra · Mar 26, 2013 · Viewed 7.6k times · Source

This is kind of a specific issue but I imagine it might come in useful at some point for someone else if I can find a solution.

I've got a need to convert some of my Highcharts graphs into PNGs on the browser end. The idea is that when our authors are creating a graph it'll get automatically converted to a PNG and that PNG will be saved along with the JS code for the given graph. Then we can serve that PNG version up in situations where JS isn't an option. I've got this all working via the canvg library and it's perfect.

Well, almost. Because of all of the high dpi screens out there we want the PNG to be scaled up twice as big as the graphs are normally displayed. So that way the PNG version can look good on iPhone's/iPads, etc...

canvg has some scaling options so I attempted to use those. But that's where it starts to break down. The graph is scaled correctly but there's a box somewhere in the Highcharts object that doesn't get scaled along with everything else and the resulting scaled graph shows just the top left corner of the beautifully scaled graph.

I looked at the canvg code and realized pretty quickly my JS abilities aren't good enough to figure what's happening, same thing for the Highcharts end.

If anyone has ideas or knows of a simple solution for this I'd be extremely grateful.

To replicate the issue you can take a look at this JSFIDDLE example I put together:

http://jsfiddle.net/UVNvh/3/

And here's the code if that JSFIDDLE page gets messed up or disappears somehow.

<script src="http://code.highcharts.com/highcharts.js">http://code.highcharts.com/highcharts.js</script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>
<script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/rgbcolor.js"></script> 
<script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/canvg.js"></script> 
<p>Highcharts</p>
<div id="container" style="height: 400px; margin-top: 1em"></div>
<p>Canvas</p>
<canvas id="canvas"></canvas>
<p>Image</p>
<div id="image"><div>

<script type="text/javascript">
$(function () {
    var chart = new Highcharts.Chart({

        chart: {
            renderTo: 'container'
        },

        credits: {
            enabled: false
        },

        xAxis: {
            categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
        },

        series: [{
            data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]        
        }],

        navigation: {
            buttonOptions: {
                enabled: false
            }
        },
        exporting: {
            type: 'image/jpeg'
        }

    });

    var chart_svg = chart.getSVG();                    
    var chart_canvas = document.getElementById('canvas');

    canvg(chart_canvas, chart_svg, {scaleWidth: 1280, scaleHeight: 860});

    var chart_img = chart_canvas.toDataURL('image/png');

    jQuery('#image').append('<img src="' + chart_img + '" />');
});
</script>

Answer

Mar&#231;al Juan picture Marçal Juan · Nov 18, 2013

I improved Scott Gearhart without hacks :) http://jsfiddle.net/marcalj/EsPud/7/

Most important part:

// Get chart aspect ratio
var c_ar = chart.chartHeight / chart.chartWidth;

// Set canvas size
chart_canvas.width = 1280;
chart_canvas.height = chart_canvas.width * c_ar;

canvg(chart_canvas, chart_svg, {
    ignoreDimensions: true,
    scaleWidth: chart_canvas.width,
    scaleHeight: chart_canvas.height
});

Make sure you set fixed width and height on chart element.