简体   繁体   中英

KnpLabs/snappy bundle (wkhtmltopdf) not render Chart.js charts

I trying to generate PDF with charts generated by Chart.js library but javascript does not render at all.

Do you see something I had missed?

   # config/packages/knp_snappy.yaml
    knp_snappy:
        pdf:
            enabled:    true
            binary:     '%env(WKHTMLTOPDF_PATH)%'
            options:
              debug-javascript: true
              enable-javascript: true
              javascript-delay: 200
              no-stop-slow-scripts: true

        image:
            enabled:    true
            binary:     '%env(WKHTMLTOIMAGE_PATH)%'
            options:    []

PHP Symfony part

    /**
     * Download pdf.
     *
     * @param string $slug
     * @param string $language
     *
     * @return Response
     *
     * @throws \Psr\Cache\CacheException
     * @throws \Psr\Cache\InvalidArgumentException
     */
    public function __invoke(string $slug, string $language): Response
    {
            $this->pdfFilesService->setPdfLanguage($language);
            $base64Images = $this->pdfFilesService->getBase64Images($slug);
            $profile      = $this->profileData->execute($slug, $language);
            $filename     = $profile['name'].'-report.pdf';
            $path         = $this->parameterBag->get('app.private_pdf_storage').'/'.$filename;

            $html = $this->templating->render('download_pdf.twig', \array_merge($base64Images, [
                'profile'     => $profile,
                'language'    => $language,
            ]));


            $this->pdf->generateFromHtml([$html], $path, [], true);

            return new Response(
                $path,
                200,
                [
                    'Content-Type'        => 'application/pdf',
                    'Content-Disposition' => 'inline; filename="'.$path.'"',
                ]
            );

    }

Twig

   <section>
       <div id="barMulti"></div>
   </section>
   <script type="text/javascript" src="{{ chartJs }}"></script>
   <script type="text/javascript">
      function getDataMulti(type) {
         return {
            // The type of chart we want to create
            type,

            // The data for our dataset
            data: {
               labels: [ ... ],
               datasets: [
                  {
                     backgroundColor: "#F4F7F9",
                     data: [3,7,4,5,5,2,6,8,9,7]
                  },
                  {
                     backgroundColor: "#66C4E0",
                     data: [3,7,4,5,5,2,6,8,9,7]
                  },
                  {
                     backgroundColor: "#009DCD",
                     data: [3,7,4,5,5,2,6,8,9,7]
                  },
               ]
            },

            // Configuration options go here
            options: {
               legend: {
                  display: false,
               },
               animation: {
                  duration: 0
               },
               scales: {
                  yAxes: [{
                     gridLines: {
                        color: "#454D57",
                     },
                     ticks: {
                        padding: 20,
                        fontStyle: 'bold',
                        fontColor: '#F4F7F9',
                        min: 0,
                        max: 100,
                     }
                  }],
                  xAxes: [
                     {
                        gridLines: {
                           color: "#454D57"
                        },
                        ticks: {
                           fontStyle: 'bold',
                           fontColor: '#F4F7F9',
                           padding: 20,
                           callback: function(label) {
                              if (/\s/.test(label)) {
                                 return label.split(" ");
                              }

                              return label;
                           }
                        }
                     }
                  ]
               }
            }
         }
      }

      // var barMulti = document.getElementById('barMulti');
      var barMulti = document.getElementById('barMulti');
      new Chart(barMulti, getDataMulti('bar'));
   </script>

wkhtmltopdf is not a perfect library but it is opensource and free to use , so we need to be grateful and try to help its usage or improve by contributing.

wkhtmltopdf GitHub Repo

As the first step, you need to test your HTML/TWIG template for working Javascript.

<script>
  document.body.innerHTML = "Testing JavaScript PDF Rendering"
</script>

If this is not working then check your wkhtmltopdf configuration

  # config/packages/knp_snappy.yaml
    knp_snappy:
        pdf:
            enabled:    true
            binary:     '%env(WKHTMLTOPDF_PATH)%'
            options:
              debug-javascript: true
              enable-javascript: true
              javascript-delay: 1500
              no-stop-slow-scripts: true

After you are sure that Javascript works in wkhtmltopdf

Most important thing. You need to wrap your canvas element with styled div

 <div class="reportGraph">
     <canvas id="barMulti"></canvas>
 </div>

and in head or css put styled class

   .reportGraph {
      width:850px
   }

or maybe style canvas container by inline css

Then add this script file after including of chart.js library

<script>
  // wkhtmltopdf 0.12.5 crash fix.
  // https://github.com/wkhtmltopdf/wkhtmltopdf/issues/3242#issuecomment-518099192
  'use strict';
  (function(setLineDash) {
    CanvasRenderingContext2D.prototype.setLineDash = function() {
      if(!arguments[0].length){
        arguments[0] = [1,0];
      }
      // Now, call the original method
      return setLineDash.apply(this, arguments);
    };
  })(CanvasRenderingContext2D.prototype.setLineDash);
  Function.prototype.bind = Function.prototype.bind || function (thisp) {
    var fn = this;
    return function () {
      return fn.apply(thisp, arguments);
    };
  };
</script>

Then add another script tag in which you will render your chart.

<script>
function drawGraphs() {
    new Chart(
        document.getElementById("canvas"), {
            "responsive": false,
            "type":"line",
            "data":{"labels":["January","February","March","April","May","June","July"],"datasets":[{"label":"My First Dataset","data":[65,59,80,81,56,55,40],"fill":false,"borderColor":"rgb(75, 192, 192)","lineTension":0.1}]},
            "options":{}
        }
    );
}
window.onload = function() {
    drawGraphs();
};
</script>

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