KnpLabs/snappy 捆绑包 (wkhtmltopdf) 未呈现 Chart.js 图表

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

我试图用 Chart.js 库生成的图表生成 PDF 但是 javascript 根本不渲染。

你看到我遗漏了什么吗?

   # 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 部分

    /**
     * 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.'"',
                ]
            );

    }

树枝

   <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

作为第一步,您需要测试 HTML/TWIG 模板是否正常工作 Javascript。

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

如果这不起作用,请检查您的 wkhtmltopdf 配置

  # 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

在您确定 Javascript 在 wkhtmltopdf

中工作后

最重要的事情。 你需要用 styled div

包裹你的 canvas 元素
 <div class="reportGraph">
     <canvas id="barMulti"></canvas>
 </div>

并在 headcss 中放置样式 class

   .reportGraph {
      width:850px
   }

或者通过内联 css

样式 canvas 容器

然后在包含chart.js

之后添加这个脚本文件
<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>

然后添加另一个 script 标签,您将在其中呈现图表。

<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>