简体   繁体   中英

PhantomJs to save png image of google chart's API GeoChart

I am trying save the chart generated by google charts as a png image. The code works fine for all charts except GeoChart.The image sometimes does appears but often its just blank. Here is the code .

render.js

var system = require('system');
var page = require('webpage').create();
page.open('chart.html, function () {
    page.paperSize = { format: 'A4', orientation: 'landscape'};
    page.render(system.args[1]);
    phantom.exit();
});

chart.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Chart Generation</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" /> 
<script type='text/javascript' src='https://www.google.com/jsapi'></script>
<script type='text/javascript'>
 google.load('visualization', '1', {'packages': ['geochart']});
 google.setOnLoadCallback(drawRegionsMap);

  function drawRegionsMap() {
    var data = google.visualization.arrayToDataTable([
      ['Country', 'Popularity'],
      ['Germany', 200],
      ['United States', 300],
      ['Brazil', 400],
      ['Canada', 500],
      ['France', 600],
      ['RU', 700]
    ]);
    var options = {
      width: 400,
      height: 200
    };
    var chart = new google.visualization
      .GeoChart(document.getElementById('chart_div'));
    chart.draw(data, options);
};
</script>
</head>
<body>
<div id="chart_div" style="width: 900px; height: 500px;"></div>
</body>
</html>

Usgae in Terminal :

phantomjs render.js chart.png

Try delaying your rendering:

page.open(address, function (status) {
   window.setTimeout(function () {
        page.render(output);
        phantom.exit();
    }, 1000);
});

This will delay it by 1000ms (1 second), and should be enough time for your chart to load properly.

Actually, a timeout of 1 second is by far not enough if you use the GeoChart with Markers in text mode (instead of lat/long). A better solution is to code around a recursive function that checks if the ready event was triggered by the chart; do this in a page.evaluate:

function chartready() {
    console.log('Google.chart.ready');
}                       
var chart = new google.visualization.ChartWrapper(settings);    
chart.draw();
google.visualization.events.addListener(chart, 'ready', chartready);

and make sure you are monitoring the console.log like they do in the HighCharts phantomjs script:

page.onConsoleMessage = function (msg) {
  /*
  * Ugly hack, but only way to get messages out of the 'page.evaluate()'
  * sandbox. If any, please contribute with improvements on this!
  */
  if (msg === 'Google.chart.ready') {
    window.ischartready = true;
  }
}

And then keep calling setTimeout until window.ischartready is true (or a predefined number of seconds pass and you just give up).

timeoutTime=8000;//wait not longer than 8 seconds
interval = window.setInterval(function () {
    console.log('waiting');
    if (window.ischartready) {
        clearTimeout(timer);
        clearInterval(interval);
        page.render(whatever);
    }
}, 50);

// we have a timeoutTime second timeframe..
timer = window.setTimeout(function () {
    clearInterval(interval);
    exitCallback('ERROR: While rendering, there\'s is a timeout reached');
}, timeoutTime);

The system dosen't allow me to comment on @Jeroen answer so based on his answer I'd add this:

1- You need to register the event before calling the draw method. the-ready-event

Adding a listener to this event should be done before calling the draw() method, because otherwise the event might be fired before the listener is set up and you will not catch it.

2- Instead of using onConsoleMessage. I'd use page.onCallback ( phantom on callBack ). And of course on the chartready function I'd call window.callPhantom

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM