I am trying to use the snappy
library with wkhtmltopdf
to render a chart (LavaChart) on a generated PDF but I have not been able. The PDF generates fine but the chart does not show. If the view is not converted to PDF, the Chart is rendered as expected.
Below is my code for the LavaChart and Snappy.
The Chart Part
$chart = Lava::ColumnChart('Performance', $table, [
'title' => 'Performance Chart',
'png' => true,
'animation' => [
'startup' => true,
'easing' => 'inAndOut'
],
'titleTextStyle' => [
'fontName' => 'Arial',
'fontColor' => 'blue'
],
'legend' => [
'position' => 'top'
],
'vAxis' => [
'title' => 'Total Score'
],
'hAxis' => [
'title' => 'Class'
],
'events' => [
'ready' => 'getImageCallback'
],
'colors' => ['#3366CC','#DC2912', '#FF9900']
]);
The Snappy Part
$pdf = PDF::loadView('print.charts')->setPaper('portrait');
$pdf->setOption('enable-javascript', true);
$pdf->setOption('javascript-delay', 10000);
$pdf->setOption('no-stop-slow-scripts', true);
$pdf->setOption('page-size', 'A4');
$pdf->setOption('margin-left', 0);
$pdf->setOption('margin-right', 0);
$pdf->setOption('margin-top', 0);
$pdf->setOption('margin-bottom', 0);
$pdf->setOption('lowquality', false);
$pdf->setTimeout(1500);
$pdf->setOption('disable-smart-shrinking', true);
The View Part
<script type="text/javascript">
function getImageCallback (event, chart) {
console.log(chart.getImageURI());
}
</script>
<div id="chart" style="margin: 10px; height: 200px; width: 50%;"></div>
{!! Lava::render('ColumnChart', 'Performance', 'chart') !!}
Since the chart renders as expected when the view is not converted to pdf, I have reasons to believe the wkhtmltopdf
does not execute the javascript has expected in the pdf version. I have the latest wkhtmltopdf
installed but still no luck.
Library Version:
barryvdh/laravel-snappy: ^0.4.3
khill/lavacharts: 3.0.*
Any help will be appreciated, thanks.
I can show with a simple example, At first I have shown the chart on browser, The chart example is taken from Lavacharts docs(you can use yours). Keep a Note on
events
with callback getImageCallback
.
public function index(){
$lava = new Lavacharts;
$data = $lava->DataTable();
$data->addDateColumn('Day of Month')
->addNumberColumn('Projected')
->addNumberColumn('Official');
// Random Data For Example
for ($a = 1; $a < 20; $a++) {
$rowData = [
"2020-10-$a", rand(800,1000), rand(800,1000)
];
$data->addRow($rowData);
}
$lava->LineChart('Stocks', $data, [
'elementId' => 'stocks-div',
'title' => 'Stock Market Trends',
'animation' => [
'startup' => true,
'easing' => 'inAndOut'
],
'colors' => ['blue', '#F4C1D8'],
'events' => [
'ready' => 'getImageCallback'
]
]);
return view('charts-view', ['lava' => $lava]);
}
In view charts-view,
<div id="stocks-div">
<?= $lava->render('LineChart', 'Stocks', 'stocks-div'); ?>
</div>
<form action="{{ url('export-pdf') }}" method="post">
@csrf
<div class="form-group">
<input type="hidden" name="exportpdf" id="exportPDF">
<button class="btn btn-info" type="submit">Export as PDF</button>
</div>
</form>
<script type="text/javascript">
function getImageCallback (event, chart) {
console.log(chart.getImageURI());
document.getElementById("exportPDF").value = chart.getImageURI();
}
</script>
note the function name in script must be same as the value set for ready
key in events
in the controller. Upto this step you have done as well. I have passed the result obtained by as a hidden input field and posted the form to the controller.You can see in the diagram button export as PDF
.
The url export-pdf
calls the controller function exportPdf
which willfinally generate the PDF. You need to pass the image (obtained as data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB .....
) to the controller to pass it to the view as image.
In exportPdf,
public function exportPdf(Request $request){
$imageData = $request->get('exportpdf');
$pdf = SnappyPDF::loadView('export-pdf', ['imageData' => $imageData])->setPaper('a4')->setOrientation('portrait');
$pdf->setOption('lowquality', false);
$pdf->setTimeout(1500);
$pdf->setOption('disable-smart-shrinking', true);
return $pdf->download('stock-market.pdf');
}
The export-pdf blade view
<!DOCTYPE html>
<html lang="en">
<head>
<title>Stock Market</title>
</head>
<body>
<div class="container">
<div class="col">
<h2>Stock Market Detail</h2>
</div>
<div class="col">
<h4>Oct 2020</h4>
</div>
</div>
<img src="{{ $imageData }}" alt="image" width="720" height="230">
</body>
</html>