Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

highcharts and canvg scaling issue

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>
like image 847
Jamie Poitra Avatar asked Dec 08 '22 16:12

Jamie Poitra


2 Answers

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.

like image 188
Marçal Juan Avatar answered Dec 27 '22 02:12

Marçal Juan


It sound like you are working on some kind of admin tool so changing the size of the chart might not be an issue. You should probably use chart.setSize(width,height) before calling getSVG().

If you can't go that route, you could also edit the SVG text directly but that wouldn't be a best practice in my opinion.

It seems that the way canvg works is it takes the scaleWidth/scaleHeight and adds a transform="scale()" to the svg based on the options you pass and the existing height/width of the svg. The problem is it doesn't change the existing height/width of the svg and resulting image. I put together a jsfiddle that does what I think you want, but it is probably not the best solution. http://jsfiddle.net/sgearhart2/EsPud/1/

var chart_svg = chart.getSVG();                    
chart_svg = chart_svg.replace('width="600"', 'width="1280"');   
chart_svg = chart_svg.replace('height="400"', 'height="860"'); 

// If i had to guess, canvg does the next part but not the prior part  
var dWidth = 1280/600, dHeight = 860/400;
chart_svg = chart_svg.replace(
    '<svg ', 
    '<svg transform="scale(' + dWidth + ' ' + dHeight + ')" '
); 
like image 31
Scott Gearhart Avatar answered Dec 27 '22 01:12

Scott Gearhart