I could not figure out how to make Google Visualization Charts load in my pdf.
I tried with a high javascript-delay but still not working. Rendering the view works fine though.
Thanks
$pdf = \PDF::loadView('invoice', compact('data'));
$pdf->setOptions([
'enable-javascript' => true,
'javascript-delay' => 10000,
'images' => true,
'enable-smart-shrinking' => true,
'no-stop-slow-scripts' => true
]);
return $pdf->download('invoice.pdf');
I found out it was related to this issue
I tried the old way to import google charts
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
</script>
Worked fine but not the latest version...
Please let me know you figured out a solution to load the latest version. Thanks
Hi, I had this same problem, and found a solution here:
https://codingexplained.com/coding/php/using-google-visualization-with-wkhtmltopdf
basically:
// Add this script in <head>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
...
// Add onload in <body>
<body onload="init()">
...
</body>
// and the init function
function init() {
google.load("visualization", "1.1", { packages:["corechart"], callback: 'drawCharts' });
}
the drawCharts() is the same, don't need to change.
Hope it helps someone else
All the options above mentions the old library? Do any have solution with loader.j?
I remember that the charts are not to be interactive. Even the enable interactive option fails here.
All the options above mentions the old library? Do any have solution with loader.j?
I remember that the charts are not to be interactive. Even the enable interactive option fails here.
Did you find a solution? My google charts recently stopped working (it only loads 50% of the time using the /jsapi url)
All the options above mentions the old library? Do any have solution with loader.j?
I remember that the charts are not to be interactive. Even the enable interactive option fails here.Did you find a solution? My google charts recently stopped working (it only loads 50% of the time using the /jsapi url)
Use Loader.js library and put a setTimeout() on the chart callback like this
setTimeout(function(){
google.charts.setOnLoadCallback(drawGenderChart());
}, 500);
drawGenderChart() is the function which draws the chart.
I think you need to tell wkhtmltopdf to wait for you to be ready. There is an option to wait for a status, by setting the title. The you could add a callback when the rendering is finished to update the page title.
Or you could try disabling animations etc.
Thank you! This worked!
For reference:
google.charts.load('current', {packages: ['corechart']});
var interval = setInterval(function() {
if (
google.visualization !== undefined
&& google.visualization.DataTable !== undefined
&& google.visualization.PieChart !== undefined
){
clearInterval(interval);
window.status = 'ready';
drawCharts();
}
}, 100);
Anyone having this problem,
The Solution that I was using <script type="text/javascript" src="https://www.google.com/jsapi"></script> stop working.
The solution points by @Abisco Works great for me. Thanks
Had the same problem, tried everything else, but the solution provided by @Abisco solved it. Thank you!
I had this same issue, tried @Abisco solution but it didn't work too.
$pdf = SnappyPDF::loadView('report', []);
$pdf->setOption('enable-javascript', true);
$pdf->setOption('no-stop-slow-scripts', true);
$pdf->setOption('margin-bottom', 0);
$pdf->setOption('margin-top', 0);
$pdf->setOption('margin-left', 0);
$pdf->setOption('margin-right', 0);
$pdf->setOption('page-size', 'A4');
$pdf->setOption('lowquality', false);
$pdf->setOption('disable-smart-shrinking', true);
$pdf->setOption('images', true);
$pdf->setOption('window-status', 'ready');
$pdf->setOption('run-script', 'window.setTimeout(function(){window.status="ready";},5000);');
return $pdf->inline();
<head>
<script src="http://www.gstatic.com/charts/loader.js"></script>
<script>
function init() {
google.charts.load('current', {packages: ['corechart']});
var interval = setInterval(function () {
if (google.visualization !== undefined && google.visualization.DataTable !== undefined && google.visualization.PieChart !== undefined) {
clearInterval(interval);
window.status = 'ready';
drawChart();
}
}, 100);
}
function drawChart() {
// Define the chart to be drawn.
var data = new google.visualization.DataTable();
data.addColumn('string', 'Element');
data.addColumn('number', 'Percentage');
data.addRows([
['Nitrogen', 0.78],
['Oxygen', 0.21],
['Other', 0.01]
]);
var chart = new google.visualization.PieChart(document.getElementById('myPieChart'));
chart.draw(data, null);
}
</script>
</head>
<body onload="init()">
md5-153df5499f0b9963e890db2b4213f1a7
</body>
Update:
Solved the issue by using wkhtmltopdf 0.12.5
Thank you! This worked!
For reference:
google.charts.load('current', {packages: ['corechart']}); var interval = setInterval(function() { if ( google.visualization !== undefined && google.visualization.DataTable !== undefined && google.visualization.PieChart !== undefined ){ clearInterval(interval); window.status = 'ready'; drawCharts(); } }, 100);
DUDE. I litterally spent DAYS struggling with this problem, this just solved it. MVP here. Thanks !
Encountered this issue recently. I have tried all the workarounds to fix the loading issue - setOnLoadCallback, delays, setInterval, setTimeout. Also tried upgrading the wkhtml version.
What worked for me is explicitly define the Google Charts version number to use. In my case version 44.
<script>google.load("visualization", "44", {packages:["corechart"]});</script>
Note: using version "1" now means you are using the current version. Per Google document - "All 'jsapi' requests are now being redirected to the new loader. If you were loading version '1' or '1.0', you will now be loading 'current'."
Same problem here.
I'm actually using wkhtmltopdf 0.12.5, tried to use <script type="text/javascript" src="http://www.gstatic.com/charts/loader.js"></script> instead of "http://www.google.com/jsapi",
and i'm using that code:
<script type="text/javascript">
function init() {
google.load("visualization", "44", {
packages: ["corechart"],
callback: function () {
drawCharts();
}
});
}
function drawCharts() {
var array = JSON.parse('{{json_encode($keys)}}');
var notes = {!! json_encode($graphic_notes) !!};
console.log(notes);
for (var i = 0; i < array.length; i++) {
var div = 'columnchart_' + array[i];
var options = {
titleY: 'Result (0-100%)',
titleX: 'Disciplinas',
min: '0',
max: '100'
};
var index = array[i];
var variable = notes[index].substr(1);
console.log(variable);
variable = variable.substr(0, variable.length - 1).split('], [');
for (var z = 0; z < variable.length; z++) {
variable[z] = variable[z].split(',');
if (z > 0) {
for (var o = 1; o < variable[z].length; o++) {
variable[z][o] = parseFloat(variable[z][o]);
}
}
}
var data = google.visualization.arrayToDataTable(variable);
var chart = new google.visualization.ColumnChart(document.getElementById(div));
chart.draw(data, options);
}
}
</script>
@foreach($codes as $code)
<div class="chart" id="columnchart_{{$code}}">
</div>
@endforeach
with the PHP code:
return PDF::loadHtml($html->render())
->setOptions(['encoding' => 'utf-8'])
->setOption('enable-javascript', true)
->setOption('javascript-delay', 5000)
->setOption('enable-smart-shrinking', true)
->setOption('no-stop-slow-scripts', true)
->setPaper('a4')
->setOrientation('landscape')
->stream();
When i just return html->render() the page correctly show the chart, but returns blank page on PDF.
Was working, but stopped.
I resolved removing the "callback":
function init() {
google.load("visualization", "44", {
packages: ["corechart"]
});
{
var interval = setInterval(function () {
if (google.visualization !== undefined && google.visualization.DataTable !== undefined
&& google.visualization.ColumnChart !== undefined) {
clearInterval(interval);
drawCharts();
window.status = 'ready';
}
}, 100);
}
}
I resolved removing the "callback":
function init() { google.load("visualization", "44", { packages: ["corechart"] }); { var interval = setInterval(function () { if (google.visualization !== undefined && google.visualization.DataTable !== undefined && google.visualization.ColumnChart !== undefined) { clearInterval(interval); drawCharts(); window.status = 'ready'; } }, 100); } }
And again, it was broken. Thank you mate, you saved me. It begins to be really complicated to generate PDF with charts with laravel-snappy, honestly. I'm thinking about switching to a front end generator...
Hi @runerod, I agree with you, its really very complicated. But its not a problem of barryvdh/laravel-snappy package. It's just a wrapper for wkhtmltopdf. This package is great, but wkhtmltopdf has too many problem with this kind of content (render chart).
After have too may problem with wkhtmltopdf, I finally moved out. I'm using now Google Chrome Headless. Its great. I use this wrapper: https://github.com/spatie/browsershot. It`s working great and is much faster.
With Chrome headless you need to use ->waitUntilNetworkIdle() for the chart generation work. See: https://github.com/spatie/browsershot#waiting-for-lazy-loaded-resources
Hi @runerod, I agree with you, its really very complicated. But its not a problem of
barryvdh/laravel-snappypackage. It's just a wrapper forwkhtmltopdf. This package is great, butwkhtmltopdfhas too many problem with this kind of content (render chart).After have too may problem with wkhtmltopdf, I finally moved out. I'm using now Google Chrome Headless. Its great. I use this wrapper: https://github.com/spatie/browsershot. It`s working great and is much faster.
With Chrome headless you need to use
->waitUntilNetworkIdle()for the chart generation work. See: https://github.com/spatie/browsershot#waiting-for-lazy-loaded-resources
Thanks for the reply @Henryavila ! You are right, the problem seems to be proper to wkhtmltopdf only.
By the way, the fact is that I generate a PDF but not showing it on a webpage. It's a PDF automatically generated from a view in Laravel, so my question is : Chrome Headless seems to generate a PDF from a webpage, BUT does it will work in my case too... ? I will take a look anyway but i'm curious to know.
Thanks for the reply @henryavila ! You are right, the problem seems to be proper to wkhtmltopdf only.
By the way, the fact is that I generate a PDF but not showing it on a webpage. It's a PDF automatically generated from a view in Laravel, so my question is : Chrome Headless seems to generate a PDF from a webpage, BUT does it will work in my case too... ? I will take a look anyway but i'm curious to know.
@runerod, I'm generating the pdf from laravel view too.
Here is the code I'm running in production (code extracted and adapted)
$view = \Illuminate\Support\Facades\View::make($viewName, $data, $mergeData);
$handler = \Spatie\Browsershot\Browsershot::html($view);
// Set any of puppeteer option. see: https://github.com/puppeteer/puppeteer/blob/v1.9.0/docs/api.md#pagepdfoptions
$handler->setOption('format', 'A4');
$handler->setOption('landscape', 'false');
// see more example in https://github.com/spatie/browsershot#usage
// Pass any argument to Headless Chrome itself
// Sell all possible aruments here: https://peter.sh/experiments/chromium-command-line-switches/
$handler->addChromiumArguments([
'font-render-hinting' => 'none', // Fix text align in pdf
])
// Necessary for chart to work. The Chrome will wait until all scripts are loaded
$handler->waitUntilNetworkIdle();
// "screen" or "print" (default). using screen allow to generate a pdf exctly as displayed in browser
$handler->emulateMedia('screen');
// get the pdf as raw data (encoded string). Usefull when attaching data in Email
$handler->pdf();
// Save the pdf in the $filePath location
$handler->save($filePath);
Hope it helps.
Thanks for the reply @henryavila ! You are right, the problem seems to be proper to wkhtmltopdf only.
By the way, the fact is that I generate a PDF but not showing it on a webpage. It's a PDF automatically generated from a view in Laravel, so my question is : Chrome Headless seems to generate a PDF from a webpage, BUT does it will work in my case too... ? I will take a look anyway but i'm curious to know.@runerod, I'm generating the pdf from laravel view too.
Here is the code I'm running in production (code extracted and adapted)$view = \Illuminate\Support\Facades\View::make($viewName, $data, $mergeData); $handler = \Spatie\Browsershot\Browsershot::html($view); // Set any of puppeteer option. see: https://github.com/puppeteer/puppeteer/blob/v1.9.0/docs/api.md#pagepdfoptions $handler->setOption('format', 'A4'); $handler->setOption('landscape', 'false'); // see more example in https://github.com/spatie/browsershot#usage // Pass any argument to Headless Chrome itself // Sell all possible aruments here: https://peter.sh/experiments/chromium-command-line-switches/ $handler->addChromiumArguments([ 'font-render-hinting' => 'none', // Fix text align in pdf ]) // Necessary for chart to work. The Chrome will wait until all scripts are loaded $handler->waitUntilNetworkIdle(); // "screen" or "print" (default). using screen allow to generate a pdf exctly as displayed in browser $handler->emulateMedia('screen'); // get the pdf as raw data (encoded string). Usefull when attaching data in Email $handler->pdf(); // Save the pdf in the $filePath location $handler->save($filePath);Hope it helps.
Thanks for the snippet. I will make a try in a future update from my customer. Actually, the less I touch the PDF part, the happier I am ! :-D
Any current solution? I couldn't make it work with version 0.12.6 of wkhtmltopdf. When I use window.status it just freezes and never finishes loading the pages.
Most helpful comment
Thank you! This worked!
For reference:
google.charts.load('current', {packages: ['corechart']}); var interval = setInterval(function() { if ( google.visualization !== undefined && google.visualization.DataTable !== undefined && google.visualization.PieChart !== undefined ){ clearInterval(interval); window.status = 'ready'; drawCharts(); } }, 100);