I have a simple report page, and I am using Laravel 7
to build it.
I want to trigger auto-download a PDF with that view.
What would be the most lightweights I should look into? I did a quick Google, and I saw so many options.
I decided to try this and did all the steps, below is my final code
Final Codes
Note this line : $pdf = PDF::loadView('layouts.be.baby.report', get_defined_vars());
public function downloadReportPDF($id) {
$code = Request::get('code');
$baby = Baby::where('adminCode',$code)->where('id',strtolower($id))
->orWhere('readOnlyCode',$code)->where('id',strtolower($id))
->first();
if($baby){
$inputs = Request::all();
$interval = 'week';
if(array_key_exists('interval', $inputs)){
$interval = $inputs['interval'];
}
switch ($interval) {
case 'day':
$q = BabyLog::where('created_at', '>', now()->today());
break;
case 'week':
$q = BabyLog::where('created_at', '>', now()->subWeek());
break;
case 'month':
$q = BabyLog::where('created_at', '>', now()->subMonth());
break;
case 'year':
$q = BabyLog::where('created_at', '>', now()->subYear());
break;
default:
$q = BabyLog::orderBy('created_at', 'desc');
break;
}
$logs = $q->where('babyId',$baby->id)->orderBy('created_at', 'desc')->get()->groupBy(function ($log) {
return $log->created_at->format('m/d/y');
});
// dd($logs);
$graphData = [];
foreach($logs as $date => $logsOnThatDay){
$pee = 0;
$poop = 0;
$feed = 0;
$medicine = 0;
$sleep = 0;
foreach($logsOnThatDay as $logOnThatDay){
// if(strtotime($logOnThatDay->created_at) < strtotime(date('Y-m-d H:i:s'))){
if($logOnThatDay->type == 'pee'){
$pee++;
}
if($logOnThatDay->type == 'poop'){
$poop++;
}
if($logOnThatDay->type == 'feed'){
$feed++;
}
if($logOnThatDay->type == 'medicine'){
$medicine++;
}
if($logOnThatDay->type == 'sleep'){
$sleep++;
}
$graphData[$date]['pee'] = $pee;
$graphData[$date]['poop'] = $poop;
$graphData[$date]['feed'] = $feed;
$graphData[$date]['medicine'] = $medicine;
$graphData[$date]['sleep'] = $sleep;
}
}
array_pop($graphData);
//PDF
$pdf = PDF::loadView('layouts.be.baby.report', get_defined_vars());
return $pdf->download('file.pdf');
}
}
It is working, when I visit the route :
Route::get('/baby/{id}/report/download','BabyController@downloadReportPDF');
But the styles seems very messed up.
- Images are missing, and so on.
How do I improve on that ?
Updated
I've updated my images links to remote url now... they loaded now.
Somehow styles still messed up.
I even tried inline style for my padding, and still rendering wrong... :(
report.blade.php
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="author" content="Bunlong Heng">
<meta name="csrf-token" value="{{ csrf_token() }}">
<title>Report</title>
<link id="favicon" rel="shortcut icon" href="{{$baby->babyProfilePath}}?q={{microtime()}}" type="image/x-icon" />
<link rel="shortcut icon" href="{{$baby->babyProfilePath}}?q={{microtime()}}" type="image/favicon.ico" />
<link rel="apple-touch-icon" href="{{$baby->babyProfilePath}}?q={{microtime()}}" sizes="152x152">
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://www.chartjs.org/dist/2.8.0/Chart.min.js"></script>
<script src="https://www.chartjs.org/samples/latest/utils.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<style type="text/css">
body {
background-color: white;
color: black;
}
h5 {
font-weight: normal;
color: #86868b;
}
.text-poop {
border: #ffb54c 1px solid !important;
color: #ffb54c;
}
.text-pee {
border: #46b8da 1px solid !important;
color: #46b8da;
}
.text-medicine {
border: #ffdf0a 1px solid !important;
color: #ffdf0a;
}
.text-sleep {
border: #ca88ff 1px solid !important;
color: #ca88ff;
}
.text-feed {
border: black 1px solid !important;
color: black;
}
</style>
</head>
<body>
<div class="container ">
<div class="row ">
<div class="col-sm-2 "></div>
<div class="col-sm-8">
<h1>{{ $baby->babyName }}</h1>
<hr>
<h5> Interval : {{ $interval }}ly. </h5>
<h5> Today : {{ date('D F j, Y, g:i a') }}</h5>
<h5> Parents : {{ $baby->name }} ({{ $baby->email }})</h5>
<h5> URL : {{ env('APP_URL') }}/baby/{{ $baby->id }}/report?code={{ $baby->readOnlyCode }}</h5>
<hr>
<canvas id="canvas"></canvas>
<hr>
<table class="table skill-table">
<thead class="thin-border-bottom">
<th>date</th>
<th>Ago</th>
<th><img src="https://i.imgur.com/Xhg4Iwi.png" /> </th>
<th><img src="https://i.imgur.com/peU9Bas.png" /> </th>
<th><img src="https://i.imgur.com/Y3rrj9T.png" /> </th>
<th><img src="https://i.imgur.com/zQrE1o5.png" /> </th>
<th><img src="https://i.imgur.com/yCk62aM.png" /> </th>
</thead>
<tbody>
@foreach ($graphData as $date => $graph)
<tr>
<td >
{{$date}}
</td>
<td>{{ DateHelper::ago($date) }} ago.</td>
<td >
<a style="padding: 5px; " class="text-poop">{{$graph['poop'] ?? '' }}</a>
</td>
<td >
<a style="padding: 5px; " class="text-pee">{{$graph['pee'] ?? '' }}</a>
</td>
<td >
<a style="padding: 5px; " class="text-feed">{{$graph['feed'] ?? '' }}</a>
</td>
<td >
<a style="padding: 5px; " class="text-medicine">{{$graph['medicine'] ?? '' }}</a>
</td>
<td >
<a style="padding: 5px; " class="text-sleep">{{$graph['sleep'] ?? '' }}</a>
</td>
</tr>
@endforeach
</div>
</div>
</div>
<script type="text/javascript">
function hexToRgb(hex, opacity=1) {
var h=hex.replace('#', '');
h = h.match(new RegExp('(.{'+h.length/3+'})', 'g'));
for(var i=0; i<h.length; i++)
h[i] = parseInt(h[i].length==1? h[i]+h[i]:h[i], 16);
if (typeof opacity != 'undefined') h.push(opacity);
return 'rgba('+h.join(',')+')';
}
var url_string = window.location.href;
var url = new URL(url_string);
var data = {};
if(url.searchParams.get("interval") != null){
data.interval = url.searchParams.get("interval");
}
// console.log(data.interval);
$.ajax({
method: 'POST',
url: '/baby/{{$id}}/graphsData',
crossDomain: true,
contentType: false,
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('value'),
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
"Cache-Control": "no-cache"
},
data: data,
success: function(response){
// console.log(response);
keys = [];
peeData = [];
poopData = [];
feedData = [];
medicineData = [];
sleepData = [];
$.each(response, function(key,val) {
keys.push(key);
peeData.push(val.pee);
poopData.push(val.poop);
feedData.push(val.feed);
medicineData.push(val.medicine);
sleepData.push(val.sleep);
});
// console.log(peeData, poopData, feedData, medicineData, sleepData);
var originalLineDraw = Chart.controllers.line.prototype.draw;
Chart.helpers.extend(Chart.controllers.line.prototype, {
draw: function() {
originalLineDraw.apply(this, arguments);
var chart = this.chart;
var ctx = chart.chart.ctx;
var index = chart.config.data.lineAtIndex;
if (index) {
var xaxis = chart.scales['x-axis-0'];
var yaxis = chart.scales['y-axis-0'];
ctx.save();
ctx.beginPath();
ctx.moveTo(xaxis.getPixelForValue(undefined, index), yaxis.top);
ctx.strokeStyle = '#ff0000';
ctx.textAlign = '#ff0000';
ctx.fillText('NOW',0,0);
ctx.lineTo(xaxis.getPixelForValue(undefined, index), yaxis.bottom);
ctx.stroke();
ctx.restore();
}
}
});
var options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false };
var fullDayText = new Date().toLocaleTimeString('en-us', options);
var chartColors = [hexToRgb('#fff',1), hexToRgb("ccc",1)];
let canvas = document.getElementById('canvas').getContext('2d');
canvas.height = 2000;
var renderChart = function() {
new Chart(canvas, {
type:'bar',
data:{
labels: keys,
datasets:[
{
label: 'poop',
data: poopData,
backgroundColor: hexToRgb('#ffb54c',.5),
borderWidth:1,
borderColor: hexToRgb('#ffb54c',1),
hoverBorderWidth:3,
},
{
label: 'pee',
data: peeData,
backgroundColor: hexToRgb('#46b8da',.5),
borderWidth:1,
borderColor: hexToRgb('#46b8da',1),
hoverBorderWidth:3,
},
{
label: 'feed',
data: feedData,
backgroundColor: hexToRgb('#fff',.5),
borderWidth:1,
borderColor: hexToRgb('#ccc',1),
hoverBorderWidth:3,
},
{
label: 'medecine',
data: medicineData,
backgroundColor: hexToRgb('#ffdf0a',.5),
borderWidth:1,
borderColor: hexToRgb('#ffdf0a',1),
hoverBorderWidth:3,
},
{
label: 'sleep',
data: sleepData,
backgroundColor: hexToRgb('#ca88ff',.5),
borderWidth:1,
borderColor: hexToRgb('#ca88ff',1),
hoverBorderWidth:3,
}
],
lineAtIndex: new Date().getHours()
},
options:{
legend:{
display:true,
position:'right',
labels:{
fontColor:'#000'
}
}
}
});
};
renderChart();
setTimeout(renderChart(), 1000);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log(JSON.stringify(jqXHR));
console.log("AJAX error: " + textStatus + ' : ' + errorThrown);
}
});
</script>
</body>
</html>