web-dev-qa-db-fra.com

Page avec plusieurs graphiques chart.js en pdf

J'ai utilisé chart.js pour générer une page de rapport contenant plusieurs graphiques. J'ai besoin d'exporter ce rapport au format PDF. Il existe de nombreuses solutions disponibles via la recherche, mais je ne trouve pas celle qui a plusieurs éléments de canevas.

La seule solution disponible semble être de parcourir toutes les images, de recréer le rapport à l'aide des images, puis de le télécharger au format PDF.

Existe-t-il un moyen plus simple/plus efficace pour y parvenir?

<body>
<h1> Chart 1 </h1>
<div style="width:800px; height:400px;">
<canvas id="chart_1" width="50" height="50"></canvas>
</div>

<h1> Chart 2 </h1>
<div style="width:800px; height:400px;">
<canvas id="chart_2" width="50" height="50"></canvas>
</div>

<h1> Chart 3 </h1>
<div style="width:800px; height:400px;">
<canvas id="chart_3" width="50" height="50"></canvas>
</div>
</body>
8
Sainath Krishnan

Honnêtement, il semble que l'approche la plus simple serait de simplement fournir un lien "télécharger au format PDF" qui affiche la page d'impression du navigateur et de demander à l'utilisateur de sélectionner "imprimer en pdf".

Si cette approche ne fonctionne pas pour vous (ou vos utilisateurs), alors voici une façon approximative de le faire.

Fondamentalement, nous créons un nouvel élément canvas qui est la taille de votre page de rapport et peignons progressivement les pixels de vos graphiques chart.js canvas existants dans le nouveau canvas. Une fois cela fait, vous pouvez utiliser jsPDF pour ajouter le nouveau canevas à un document pdf en tant qu'image et télécharger le fichier.

Voici un exemple d'implémentation qui fait exactement cela.

$('#downloadPdf').click(function(event) {
  // get size of report page
  var reportPageHeight = $('#reportPage').innerHeight();
  var reportPageWidth = $('#reportPage').innerWidth();

  // create a new canvas object that we will populate with all other canvas objects
  var pdfCanvas = $('<canvas />').attr({
    id: "canvaspdf",
    width: reportPageWidth,
    height: reportPageHeight
  });

  // keep track canvas position
  var pdfctx = $(pdfCanvas)[0].getContext('2d');
  var pdfctxX = 0;
  var pdfctxY = 0;
  var buffer = 100;

  // for each chart.js chart
  $("canvas").each(function(index) {
    // get the chart height/width
    var canvasHeight = $(this).innerHeight();
    var canvasWidth = $(this).innerWidth();

    // draw the chart into the new canvas
    pdfctx.drawImage($(this)[0], pdfctxX, pdfctxY, canvasWidth, canvasHeight);
    pdfctxX += canvasWidth + buffer;

    // our report page is in a grid pattern so replicate that in the new canvas
    if (index % 2 === 1) {
      pdfctxX = 0;
      pdfctxY += canvasHeight + buffer;
    }
  });

  // create new pdf and add our new canvas as an image
  var pdf = new jsPDF('l', 'pt', [reportPageWidth, reportPageHeight]);
  pdf.addImage($(pdfCanvas)[0], 'PNG', 0, 0);

  // download the pdf
  pdf.save('filename.pdf');
});

Vous pouvez le voir en action à ce codepen .

Parlons maintenant de quelques pièges avec cette approche. Tout d'abord, vous devez contrôler la position de chaque chart.js canvas dans le nouvel objet canvas. La seule façon de le faire est de comprendre comment votre page de rapport est structurée et de mettre en œuvre cette même structure. Dans mon exemple, mes graphiques sont dans une grille 2x2 et la logique gère cela en conséquence. Si vous aviez une grille 3x2 ou quelque chose de différent, vous devrez changer la logique de positionnement.

Enfin, les dimensions finales du fichier de sortie PDF sont beaucoup plus grandes que la page du graphique d'origine (sur le Web). Je pense que la raison en est que mon graphique "conteneur" div s'étend sur toute la page. Par conséquent, vous souhaiterez probablement utiliser une approche différente pour définir la taille de votre nouveau canvas.

Pour faire court, l'exemple ci-dessus est destiné à démontrer une approche et non à être votre solution finale.

Bonne chance!

16
jordanwillis