Create dynamic pdf content using jsPDF - javascript

I would generate a pdf with a dynamic content.
The text content could change so their positions also
Actually I'm fixing statically text position, but when the text content change their width is not the same and this is consing overlapping content.
const pdf = new jsPDF('l', 'px', 'a4');
pdf.internal.scaleFactor = 0.75;
const elm = this.logoActivity.nativeElement.src;
pdf.addImage(elm, 'png', 20, 20, 50, 16);
pdf.setFontType("bold");
pdf.setTextColor(255, 182, 18);
pdf.text(150, -280, "dynamic txt");
pdf.setTextColor(0, 0, 0);
pdf.text(30, -250, _.startCase(this.dateOfTheDay));
console.log(this.filterService.filters$.value);
pdf.text(100, -250, this.activityService.activity);
pdf.save(`finename.pdf`);
I would like to know how can I place element as in HTML page ( next element is placed after).
Should I create an HTML template then use html2canvas to render it ? The problem with html2canvas is that it generates an image/canvas so the text quality is not as good as jspdf add-elements methods.
is there other solutions ?

Related

can we convert docx file into PDF using javascript without js libraries

I want to create LWC component in which I have one file selector which is uploading '.pdf', '.png','.jpg','.jpeg','.docx','.doc' types of file in salesforce. but on button click I want that file to get converted into PDF and gets download immediately.
Is it possible to convert file using js in LWC?.
I got this code but it is only working on string containing HTML element. I want it to work on whole file.
window.jsPDF = window.jspdf.jsPDF;
var doc = new jsPDF();
// Source HTMLElement or a string containing HTML.
var elementHTML = document.querySelector("#content");
doc.html(elementHTML, {
callback: function(doc) {
// Save the PDF
doc.save('sample-document.pdf');
},
margin: [10, 10, 10, 10],
autoPaging: 'text',
x: 0,
y: 0,
width: 190, //target width in the PDF document
windowWidth: 675 //window width in CSS pixels
});

Page with multiple chart.js charts to pdf

I have used chart.js to generate a report page that has multiple charts. I need to export this report to PDF. There are many solutions available via search, but I cannot find one which has multiple canvas elements.
The only available solution seems to be to loop through all the images, and recreate the report using the images, and then download that as a pdf.
Is there any simpler/more efficient way to accomplish this?
<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>
Honestly, it seems like the easiest approach would be to just provide a "download to PDF" link that pops up the browser's print page and instruct to user to select "print as pdf".
If that approach doesn't work for you (or your users), then here is a rough way to do it.
Basically, we create a new canvas element that is the size of your report page and incrementally paint the pixels from your existing chart.js canvas charts into the new canvas. Once that is done, then you can use jsPDF to add the new canvas to a pdf document as an image and download the file.
Here is an example implementation that does just that.
$('#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');
});
You can see it in action at this codepen.
Now let's talk about some gotchas with this approach. First, you have to control the position of each chart.js canvas in the new canvas object. The only way to do that is to have an understanding of how your report page is structured and implement that same structure. In my example, my charts are in a 2x2 grid and the logic handles this accordingly. If you had a 3x2 grid or something different then you would have to change the positioning logic.
Lastly, the final pdf output file dimensions are much larger than the original chart page (from the web). I think the reason is because my chart "container" div stretches across the full page. Therefore, you probably want to use a different approach for setting the size of your new canvas.
So long story short, the above example is meant to demonstrate an approach and not be your final solution.
Good luck!
I have a working solution in vanilla javascript(although I used ts typing) and using the lib jsPdf, where you need a plot per pdf page:
let index = 1;
// create new pdf object
// if don't choose compress as true you will end up with a large pdf file
let pdf = new jsPDF({
orientation: 'landscape',
unit: 'px',
format: 'a4',
compress: true,
})
// search for the html element(s) you need
const canvas = document.querySelectorAll("canvas");
// here my size are in pixels since I configured that in the obj instance
let pageWidth = 400;
let pageHeight = 400;
let index = 1;
// traverse the array of canvas
canvas.forEach( (canva:HTMLCanvasElement) => {
// I added some options among others I added the type of the compression
// method: FAST
pdf.addImage(canva, 'PNG', 10, 10, pageWidth, pageHeight, `img${index}`, "FAST");
// so as to not end up with an extra pdf page at the end of the iteration
if (index < canvas.length) {
pdf.addPage();
}
index++;
});
// download the pdf
pdf.save('Reporte.pdf');

Using jspdf to save html page as pdf, saved pdf contains incomplete page content if browser is zoomed, Why?

I am using jspdf and html2canvas combination to save html page as pdf. A pdf copy of current page is saved the moment you click a button. The problem is, if you zoom in the page, and then click the button, the saved pdf contains incomplete portion of the current page. Most of the part not visible on page due to zooming, gets cut off in the saved pdf page. What is the solution?
Below is the js code being invoked upon click of save button-
var pdf = new jsPDF('l', 'pt', 'a4');
var source = $('#someId')[0];
var options = {
background : '#eee'
};
pdf.addHTML(source, options, function(){
pdf.save('abcd.pdf');
});
EDIT
Taking idea from Saurabh's approach, I tried quite a similar thing, but without writing code for any extra div element. Before saving to pdf I made the screen size of a fixed width, and after printing I brought back the width back to default normal. It is working fine for, if it fails, we can always fix the height of the screen too, so that it appears fine in generated pdf despite zooming. Below is the code used by me:-
var pdf = new jsPDF('l', 'pt', 'a4');
var source = $('#someId')[0];
var options = {
background : '#eee'
};
var width = source.clientWidth;
source.style.width = '1700px';
pdf.addHTML(source, options,
function(){
pdf.save('abcd.pdf');
source.style.width = width+'px';
});
Here is how I managed to get the full page pdf while the page is zoomed in using jsPDF's new .html() method. First, I force the page zoom level back to 100% before converting it to pdf. It's important to reset the scale in html2canvas option after that, otherwise it'll returns a blank page.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.debug.js"
integrity="sha384-NaWTHo/8YCBYJ59830LTz/P4aQZK1sS0SneOgAvhsIl3zBu8r9RevNg5lHCHAuQ/"
crossorigin="anonymous"></script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<!-- html2canvas 1.0.0-alpha.11 or higher version is needed -->
<script>
function download() {
// Bring the page zoom level back to 100%
const scale = window.innerWidth / window.outerWidth;
if (scale != 1) {
document.body.style.zoom = scale;
}
let pdf = new jsPDF('p', 'pt', 'a4');
pdf.html(document.getElementById('idName'), {
html2canvas: {
scale: 1 // default is window.devicePixelRatio
},
callback: function () {
// pdf.save('test.pdf');
window.open(pdf.output('bloburl')); // to debug
}
});
}
</script>
Update: A better way is to adjust the html2canvas.scale according to the scale factor.
function download() {
let pWidth = pdf.internal.pageSize.width; // 595.28 is the width of a4
let srcWidth = document.getElementById('idName').scrollWidth;
let margin = 18; // narrow margin - 1.27 cm (36);
let scale = (pWidth - margin * 2) / srcWidth;
let pdf = new jsPDF('p', 'pt', 'a4');
pdf.html(document.getElementById('idName'), {
x: margin,
y: margin,
html2canvas: {
scale: scale,
},
callback: function () {
window.open(pdf.output('bloburl'));
}
});
}
I was going through the same problem,
To do this what I did is I made a copy of printing div and while clicking print button I attached div copy to my dom with margin-top:500px
After I got its image then I hide this copy of the div, and set margin-top:0px
I hope this will work for you.

convert web page to a pdf with styles

I want to convert a web page to PDF including all the styles I've added.
I've used jspdf.js and html2Canvas. But I got only a blur picture in PDF form.
I've searched for many JavaScript codes but didn't find a correct one.
Script I have written is:
function getPDF() {
html2canvas(document.body, {
onrendered: function(canvas) {
var img = canvas.toDataURL("Image/jpeg");
//window.open(img);
var doc = new jsPDF({
unit: 'px',
format: 'a4'
});
doc.addImage(img, 'JPEG', 0, 0, 440, 627);
doc.save("download");
}
});
}
Thank You!
There may be a few things that are contributing.
Your encoder options for the canvas.toDataURL are missing, so you're getting the defaults. The defaults may be creating a low quality image. Try this for the highest quality JPEG image:
var img = canvas.toDataURL("Image/jpeg", 1.0);
You might also try creating your jsPDF object with measurements, rather than pixels:
var pdf = new jsPDF("p", "mm", "a4"); // jsPDF(orientation, units, format)
And when you add the image, scale it to the dimensions of the page:
pdf.addImage(imgData, 'JPEG', 10, 10, 190, 277); // 190x277 mm # (10,10)mm
See if that gives you a better image quality.

how to put black text on top of gray rect in jspdf

I am using jspdf to convert my html page to PDF. So far I have figured out styles in the HTML don't apply to the PDF document. So I'm using doc.text and doc.rect.
I need the text on top of the rectangle but it seems to be that the rectangle is always on the top and it covers the text. How can I resolve this?
This is what I have tried:
var doc = new jsPDF();
doc.setFontSize(17);
doc.setTextColor(255, 0, 0);
doc.text(100,25, 'USD.00');
doc.setFillColor(255,255,200);
doc.rect(100, 20, 10, 10, 'F')
Draw your rectangle before you draw your text
var doc = new jsPDF();
doc.setFontSize(17);
doc.setFillColor(255,255,200);
doc.rect(100, 20, 10, 10, 'F');
doc.setTextColor(255, 0, 0);
doc.text(100,25, 'USD.00');
In jsPDF must be write code in sequence, then first draw the retangle and last write your text.
var doc = new jsPDF();
doc.setDrawColor(0);
doc.setFillColor(255, 0, 0);
doc.rect(40, 50, 30, 12, 'FD'); //Fill and Border
doc.setFontSize(8);
doc.setFontType('normal');
doc.text('hello', 42, 51);
You can use getTextWidth method to set proper width for a rectangle, but then you have to set font size/type before getting the width.
http://raw.githack.com/MrRio/jsPDF/master/docs/module-annotations.html#~getTextWidth

Categories

Resources