0

I am generating a chart using the Google Charts API and the data from my database, which means that there is a call to an external file and data is echoed back in a JSON format. I know that the chart can be converted to an image so I thought that this might work but unfortunately not I have tried the code below:

  google.load("visualization", "1", {packages:["corechart"]});
  google.setOnLoadCallback(drawChart);

  function drawChart() {
    var jsonData = $.ajax({
  url: "getData.php?id=<?php echo $user_id; ?>';",
  dataType:"json",
  async: false
  }).responseText;
    var data = new google.visualization.DataTable(jsonData);

   var options = {
        hAxis: {
          title: 'Audit Number'
        },
        vAxis: {
          title: 'Gross Profit %'
        }
      };
    var chart_div = document.getElementById('chart_div');
    var chart = new google.visualization.LineChart(document.getElementById('chart_div'));

   google.visualization.events.addListener(chart, 'ready', function () {
    var imgUri = chart.getImageURI();
    // do something with the image URI, like:
    document.getElementById('chartImg').src = imgUri;
});

        chart.draw(data, options);

  }

I then call include the graph on the PDF report by

   $rep_table = " <html><img id='chartImg' />

When I load the page in HTML view, it displays the chart but it's still interactive so the first issue is definitely something to do with the conversion of the chart.

The code for generating the report can be seen below

$total = db::c()->query("
        SELECT sum(value) FROM stocktake_allowances WHERE stocktake_id = '{$stocktake_id}' AND customer_id = '".$user_id."';")->fetchColumn(0);        

    $dep_qry = "SELECT
                     category_name AS category_name,allowance_date AS date, SUM(value) AS total_cost
                FROM stocktake_allowances
                ";


    $dep_qry .= " WHERE stocktake_id = '{$stocktake_id}' AND customer_id = '".$user_id."'
                  ";

    $dep_qry .= "
            GROUP BY TRIM(UPPER(category_name))
            ORDER BY category_name, allowance_date ASC";

    //echo $dep_qry;

    $dep_res = db::c()->query($dep_qry);
    $rep_table .= " <html><img id='chartImg' /><img id='chart_div' /><br/><br/><link rel='stylesheet' href='./index/style.css' type='text/css'>  <table class='st_det_rep' >
                             <tr>
                                 <td style='width:80%; text-align:center; font-size:30px;'>
                                  <img src='index/EasyCountio.png' alt='EasyCount.io' height='61' width='280'/><br/><br/><br/><br/>
                                     <strong>Wastage Summary</strong><br/>

                                 </td>

                            </tr>
                         </table>";          
    $rep_table .= "
                 <table id='stock_detail_report' cellspacing='0' style='margin-top:10px;'>
                     <tr>
                         <td class='top' style='width:30%;'><div class='nosplit'>Wastage Category</div></td>
                         <td class='top' style='width:15%;'><div class='nosplit'>Ref. No.</div></td>
                         <td class='top' style='width:15%;'><div class='nosplit'>Value</div></td>

                     </tr>";
    $sum_total_cost = 0;
    $sum_total_retail = 0;
    $sum_total_qty = 0;
    $counter = 1;
    $j=0;

     while ($row = $dep_res->fetch(PDO::FETCH_ASSOC))
    {        
        $total_cost = $row['total_cost'];//$row['unit_cost_price']*$row['qty'];
        $catName = $row['category_name'];
        $sum_total_cost += $total_cost;

        $date = date("d-M-y", strtotime($row['date']));
        $tc = number_format($total_cost, 2);

        if(!($j%2)) {
        $cssClass = 'odd';
         } else {
            $cssClass = 'even';
         }
         $j++;


        $rep_table .= "<tr>
                       <td style='text-align:right;'><div class='nosplit'>".$catName."</div></td>
                       <td style='text-align:right;'><div class='nosplit'>".$counter."</div></td>
                       <td style='text-align:right;'><div class='nosplit'>&#8364;".$total_cost."</div></td>


                    </tr>";                
        $counter++;
    }

    $stc = number_format($sum_total_cost, 2);

    $rep_table .= "<tr>
                    <td class='bottom' colspan = '2'><div class='nosplit'>Total Wastage:</div></td>

                    <td class='bottom'><div class='nosplit'>&#8364;".$stc."</div></td>
                </tr>
            </table>";

     $dompdf = new Dompdf();
     $dompdf->loadHtml($rep_table);

    // // (Optional) Setup the paper size and orientation
     $dompdf->setPaper('A4', 'l');

    // // Render the HTML as PDF
     $dompdf->render();

    // // Output the generated PDF to Browser
     $dompdf->stream("Allowances Summary.pdf", array("Attachment" => false));

The bigger issue is with including the graph on the report. When I try to generate the PDF report I get an error saying that the headers have already been sent. I used one of the tips on SO to find out what the problem is and this is what I got back:

/home/arturl/public_html/platform/class/class_report.php
21

Which corresponds to

 url: "getData.php?id=<?php echo $user_id; ?>';",

This makes perfect sense as the json string is echoed back and DOMPDF sees it as a header. Is there any other way to get this done?

ArtleMaks
  • 151
  • 3
  • 19

1 Answers1

2

when you say...

When I load the page in HTML view, it displays the chart but it's still interactive

it sounds like you want replace the chart with it's image

see following snippet...

var chart_div = document.getElementById('chart_div');
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));

google.visualization.events.addListener(chart, 'ready', function () {
  chart_div.innerHTML = '<img alt="chart" src="' + chart.getImageURI() + '" />';
});

EDIT

so i think it should flow like this...

3 pages --

  1. html page for chart
  2. getData.php
  3. buildPDF.php

html page calls getData.php and draws the chart

then when the 'ready' event fires, sends the image uri via ajax to buildPDF.php

google.visualization.events.addListener(chart, 'ready', function () {
  var imageURI = chart.getImageURI();
  chart_div.innerHTML = '<img alt="chart" src="' + imageURI + '" />';

  // send chart image
  $.ajax({
    type: 'POST',
    url: 'buildPDF.php',
    data: {
      'chartImage': imageURI,
    },
    success: function() {
      console.log('image sent');
    }
  });
});

then in buildPDF.php...

$rep_table .= " <html><img src='".$_POST['chartImage']."' />"
WhiteHat
  • 59,912
  • 7
  • 51
  • 133
  • Yes I just want to display the image. And how do I insert it into the HTML report then? Same way with the chart_div? – ArtleMaks Jan 12 '17 at 13:01
  • Ah yea, sorry my bad. You are correct, it does put an image on the HTML page. It doesn't solve the headers already sent issue with DOMPDF unfortunatelly – ArtleMaks Jan 12 '17 at 13:11
  • Please see the edit, just added more code. Let me know if you want me to include the getData.php code as well – ArtleMaks Jan 12 '17 at 14:49
  • the code that generates the pdf, recently added above, when is this run? -- i think if you draw the chart, then when the `'ready'` event fires, get the chart _image uri_. then send the _image uri_ via ajax to the php page that generates the pdf -- in pdf code, add the _image uri_ to the `src` attribute of the `` tag... – WhiteHat Jan 12 '17 at 15:23
  • I'll give this a go but I think that's where the problem occurs, dompdf seems to treat AJAX responses as headers and stops generating the PDF. I will update you after I try this solution – ArtleMaks Jan 13 '17 at 09:13
  • I tried your solution but when checking the console, I get the following error: Fatal error: Call to a member function loadHtml() on a non-object in /home/arturl/public_html/platform/buildPDF.php on line 3
    However it does say in the console "image sent". Also, the code doesn't seem to work without the chart.draw(data, options); line put I put it after the AJAX
    – ArtleMaks Jan 13 '17 at 09:37