I want to convert HTML contents to a pdf file and store it to the server so, I used jspdf - html2pdf function for convert HTML contents to pdf file.
so i am trying a javascript code in angular project like that,
var element = this.pdfTable.nativeElement
var opt = {
margin: 0.5,
filename: 'ct-scan.pdf',
enableLinks: false,
pagebreak: { mode: 'avoid-all' },
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2 },
jsPDF: { unit: 'in', format: 'a4', orientation: 'portrait' }
};
html2pdf().from(element).set(opt).toPdf().get('pdf').then(function (pdf) {
var totalPages = pdf.internal.getNumberOfPages();
for (var i = 1; i <= totalPages; i++) {
pdf.setPage(i);
pdf.setFontSize(10);
pdf.setTextColor(150);
pdf.text('Page ' + i + ' of ' + totalPages, pdf.internal.pageSize.getWidth() - 100,
pdf.internal.pageSize.getHeight() - 30);
}
}).save()
it works fine., but the header and footer are not set in the result. so anybody can help me to solve this issue? thanks in advance.
Since your unit is using inch jsPDF: { unit: 'in' ... , minus the width of 100 and the height of 30 will become negative number. The pdf won't show the text probably.
Solution: You can print the current width and height by console.log; or just divided by 2 to make it go center, then you can adjust the text to your desired position.
var element = this.pdfTable.nativeElement;
var opt = {
margin: 0.5,
filename: 'ct-scan.pdf',
enableLinks: false,
pagebreak: { mode: 'avoid-all' },
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2 },
jsPDF: { unit: 'in', format: 'a4', orientation: 'portrait' }
};
html2pdf().from(element).set(opt).toPdf().get('pdf').then(function (pdf) {
var totalPages = pdf.internal.getNumberOfPages();
//print current pdf width & height to console
console.log("getHeight:" + pdf.internal.pageSize.getHeight());
console.log("getWidth:" + pdf.internal.pageSize.getWidth());
for (var i = 1; i <= totalPages; i++) {
pdf.setPage(i);
pdf.setFontSize(10);
pdf.setTextColor(150);
//divided by 2 to go center
pdf.text('Page ' + i + ' of ' + totalPages, pdf.internal.pageSize.getWidth()/2,
pdf.internal.pageSize.getHeight()/ 2);
}
}).save();
Related
I am using eKoopman's html2pdf.js library https://github.com/eKoopmans/html2pdf.js to produce a list of recommendation for a user at the end of an assessment. These are dynamically generate based on the responses.
It works wonderfully on desktop. However when I try to output the PDF on iOS the document is blank except for the headers and footers that I add in a separate function.
Its like it completely ignores the element.
Below is the code I trigger when the user clicks a button.
var element = $('#recommendationsdisplay').html();
var opt = {
margin: [.75,0,.75,0],
filename: 'Click_Start_' + Math.floor(Date.now() / 10000) + '.pdf',
enableLinks: true,
image: {
type: 'jpeg',
quality: 1
},
html2canvas: {
scale: 2,
dpi: 300,
letterRendering: true
},
jsPDF: {
unit: 'in',
format: 'letter',
orientation: 'portrait'
},
pagebreak:{
mode: ['avoid-all', 'css', 'legacy'],
avoid: 'div.recgrid-item'
}
};
html2pdf().from(element, 'string').set(opt).toPdf().get('pdf').then(function (pdfObject) {
/* some image related encoding */
var headerTitle = "Recommendations";
var footerCR = "© 2020";
// Header and Footer
for (var i = 1; i < pdf_pages.length; i++) {
pdfObject.setPage(i);
pdfObject.setFontSize(14);
pdfObject.setTextColor('#0090DA');
pdfObject.addImage(headerData, 'PNG', 0, 0, 8.5, .5);
pdfObject.setFontSize(10);
pdfObject.setTextColor('#777777');
pdfObject.text(footerCR, 4, 10.5);
pdfObject.text(' ' + i, 7.375, 10.5);
pdfObject.addImage(logoData, 'PNG', .75, 10.25, 1, .325);
}
}).save();
EDIT: It seems like the issue is with the canvas size limitation. The element is rendered properly in the PDF if its height is NOT above a certain threshold (fewer items chosen in the assessment). My document is only a few pages long (<7)though and I have seen other users report being able to create PDFs with dozens of pages so I am not sure what the issue is.
pagebreak mode = avoid-all causing the problem. Take away 'avoid-all' .
I have resolved this issue by splitting the whole document into pages and then passing pages one by one to the html2pdf library to generate and bind all pages into a single pdf file.
Example code.
var opt = {
margin: [5, 10, 0.25, 10],
pagebreak: {mode: 'css', after: '.page2el'},
image: {type: 'jpeg', quality: 1},
filename: 'testfile.pdf',
html2canvas: {dpi: 75, scale: 2, letterRendering: true},
jsPDF: {unit: 'pt', format: 'letter', orientation: 'p'},
};
var count = 1;
let doc = html2pdf().set(opt).from(document.getElementById('page2el')).toPdf();
jQuery("#cs_pdf").find("div").each(function (e) {
// Filtering document each page with starting id with page2el
if (jQuery(this).attr('id') && jQuery(this).attr('id').indexOf('page2el') != -1) {
if (count != 1) {
doc = doc.get('pdf').then((pdf) => {
pdf.addPage();
var totalPages = jQuery("#cs_pdf").find(".page2el").length + 1;
// Adding footer text and page number for each PDF page
for (let i = 1; i <= totalPages; i++) {
pdf.setPage(i);
pdf.setFontSize(10);
pdf.setTextColor(60);
if (i !== 1) {
pdf.text('Page ' + i + ' of ' + totalPages, pdf.internal.pageSize.getWidth() - 100, pdf.internal.pageSize.getHeight() - 25);
}
if (i === 1) {
pdf.text("Confidential", pdf.internal.pageSize.getWidth() - 340, pdf.internal.pageSize.getHeight() - 35);
} else {
pdf.text(consultant_company, pdf.internal.pageSize.getWidth() - 530, pdf.internal.pageSize.getHeight() - 25);
}
}
}).from(document.getElementById(jQuery(this).attr('id'))).toContainer().toCanvas().toPdf();
}
count++;
}
// On Jquery each loop completion executing save function on doc object to compile and download PDF file
}).promise().done(function () {
doc.save();
});
You have a html table and you want to show sparkline charts from your data, exactly as in this example (from highcharts demos):
https://codepen.io/_dario/pen/rNBOGVR
Highcharts suggested code follows:
/**
* Create a constructor for sparklines that takes some sensible defaults and merges in the individual
* chart options. This function is also available from the jQuery plugin as $(element).highcharts('SparkLine').
*/
Highcharts.SparkLine = function(a, b, c) {
var hasRenderToArg = typeof a === 'string' || a.nodeName,
options = arguments[hasRenderToArg ? 1 : 0],
defaultOptions = {
chart: {
renderTo: (options.chart && options.chart.renderTo) || this,
backgroundColor: null,
borderWidth: 0,
type: 'area',
margin: [2, 0, 2, 0],
width: 120,
height: 20,
style: {
overflow: 'visible'
},
// small optimalization, saves 1-2 ms each sparkline
skipClone: true
},
title: {
text: ''
},
credits: {
enabled: false
},
xAxis: {
labels: {
enabled: false
},
title: {
text: null
},
startOnTick: false,
endOnTick: false,
tickPositions: []
},
yAxis: {
endOnTick: false,
startOnTick: false,
labels: {
enabled: false
},
title: {
text: null
},
tickPositions: [0]
},
legend: {
enabled: false
},
tooltip: {
hideDelay: 0,
outside: true,
shared: true
},
plotOptions: {
series: {
animation: false,
lineWidth: 1,
shadow: false,
states: {
hover: {
lineWidth: 1
}
},
marker: {
radius: 1,
states: {
hover: {
radius: 2
}
}
},
fillOpacity: 0.25
},
column: {
negativeColor: '#910000',
borderColor: 'silver'
}
}
};
options = Highcharts.merge(defaultOptions, options);
return hasRenderToArg ?
new Highcharts.Chart(a, options, c) :
new Highcharts.Chart(options, b);
};
var start = +new Date(),
$tds = $('td[data-sparkline]'),
fullLen = $tds.length,
n = 0;
// Creating 153 sparkline charts is quite fast in modern browsers, but IE8 and mobile
// can take some seconds, so we split the input into chunks and apply them in timeouts
// in order avoid locking up the browser process and allow interaction.
function doChunk() {
var time = +new Date(),
i,
len = $tds.length,
$td,
stringdata,
arr,
data,
chart;
for (i = 0; i < len; i += 1) {
$td = $($tds[i]);
stringdata = $td.data('sparkline');
arr = stringdata.split('; ');
data = $.map(arr[0].split(', '), parseFloat);
chart = {};
if (arr[1]) {
chart.type = arr[1];
}
$td.highcharts('SparkLine', {
series: [{
data: data,
pointStart: 1
}],
tooltip: {
headerFormat: '<span style="font-size: 10px">' + $td.parent().find('th').html() + ', Q{point.x}:</span><br/>',
pointFormat: '<b>{point.y}.000</b> USD'
},
chart: chart
});
n += 1;
// If the process takes too much time, run a timeout to allow interaction with the browser
if (new Date() - time > 500) {
$tds.splice(0, i + 1);
setTimeout(doChunk, 0);
break;
}
// Print a feedback on the performance
if (n === fullLen) {
$('#result').html('Generated ' + fullLen + ' sparklines in ' + (new Date() - start) + ' ms');
}
}
}
doChunk();
However, in my use case, the data in the table (and the data-sparkline attribute) are not hard-coded like in the example, but loaded and displayed via an AJAX call, similar to below.
//here a table row gets compiled
var tableRow = '<tr id="row_' + word.id + '">';
//this is where the sparkline data go
tableRow += '<td class="has-sparkline"></td></tr>';
//the row gets appended to tbody
$('#wordstable tbody').append(tableRow);
//finally the sparkline data are attached
//data are a simple string such as "1,2,3,4,5"
var rowId = '#row_'+word.id;
var rowIdTd = rowId + ' td.has-sparkline';
$(rowIdTd).data('sparkline',word.sparkline);
This breaks the example logic and I can't have Highcharts "see" the data.
No particular error is returned (as the data, as far as Highcharts is concerned, just isn't there, so there's nothing to do).
The doChunk bit just does all the processing in advance, and when you add your row it is no longer processing. One way of dealing with this is pulling out the part that creates a single chart into a separate function (makeChart) and when you are doing your processing you use that part directly to create your sparkline.
For example, doChunk with split out makeChart:
function makeChart(td) {
$td = td;
stringdata = $td.data('sparkline');
arr = stringdata.split('; ');
data = $.map(arr[0].split(', '), parseFloat);
chart = {};
if (arr[1]) {
chart.type = arr[1];
}
$td.highcharts('SparkLine', {
series: [{
data: data,
pointStart: 1
}],
tooltip: {
headerFormat: '<span style="font-size: 10px">' + $td.parent().find('th').html() + ', Q{point.x}:</span><br/>',
pointFormat: '<b>{point.y}.000</b> USD'
},
chart: chart
});
}
// Creating 153 sparkline charts is quite fast in modern browsers, but IE8 and mobile
// can take some seconds, so we split the input into chunks and apply them in timeouts
// in order avoid locking up the browser process and allow interaction.
function doChunk() {
var time = +new Date(),
i,
len = $tds.length,
$td,
stringdata,
arr,
data,
chart;
for (i = 0; i < len; i += 1) {
makeChart($($tds[i]));
n += 1;
// If the process takes too much time, run a timeout to allow interaction with the browser
if (new Date() - time > 500) {
$tds.splice(0, i + 1);
setTimeout(doChunk, 0);
break;
}
// Print a feedback on the performance
if (n === fullLen) {
$('#result').html('Generated ' + fullLen + ' sparklines in ' + (new Date() - start) + ' ms');
}
}
}
And then a basic example of your ajax-code:
function ajaxIsh() {
var word = {
name: 'Bird', // is the word
id: 'bird',
sparkline: '1, 2, 3, 4, 5'
};
//here a table row gets compiled
var tableRow = '<tr id="row_' + word.id + '">';
//this is where the sparkline data go
tableRow += '<th>'+word.name+'</th><td class="has-sparkline"></td></tr>';
//the row gets appended to tbody
$('#table-sparkline tbody').append(tableRow);
//finally the sparkline data are attached
//data are a simple string such as "1,2,3,4,5"
var rowId = '#row_'+word.id;
var rowIdTd = rowId + ' td.has-sparkline';
$(rowIdTd).data('sparkline',word.sparkline);
makeChart($(rowIdTd));
}
See this JSFiddle demonstration of it in action.
Currently, I am using the html2pdf library for downloading PDF files, it is working fine for me, but the problem is that after a few downloads the texts are overlapping and the complete page is broken. Using a pagebreak class I can restrict the page break issue but the overlapping issue and the broken page issue is still there. tried codes are
<div class="export-pdf" id="export-pdf">
<div class="fullWidth page-min-height">
Planned Procedure
</div>
</div>
var element = document.getElementById('export-pdf');
var opt = {
margin: [10, 0, 10, 0],
pageNumber: true,
pagebreak: {
mode: 'css',
avoid: '.breakPage',
before: '.beforeClass'
},
filename: test.pdf,
};
html2pdf().set(opt).from(element).save()
texts are overlapped I am expecting 'Planned Procedure'...if we have more data
complete pdf text become overlap after a few downloads,
Try This function
function genTablePDF(heightSize){
html2canvas(document.getElementById("HTMLtoPDF"),{
onrendered: function (canvas){
var img = canvas.toDataURL("image/png");
var doc = new jsPDF();
doc.addImage(img,'JPEG',5,8,200, +heightSize);
doc.setPage(2);
doc.internal.getNumberOfPages();
var dateName = new Date();
doc.save('PDF ( ' + dateName + ' ) ' +'.pdf'); // file name pdf
}
});
}
in last parameter the variable is for height of the page
doc.addImage(img,'JPEG',5,8,200, +heightSize);
You can pass it through function heightSize OR you can use
heightSize = document.getElementById('pageSize').value
where document.getElementById('pageSize').value is giving the numbers of rows the the page table have or you can use your business logic like:
var heightSize = document.getElementById('pageSize').value;
if( +heightSize === 7 ){
heightSize = 120;
}
if( +heightSize === 14 ){
heightSize = 200;
}
if( +heightSize === 21 ){
heightSize = 260;
}
if( +heightSize === 28 || +heightSize === 35 || +heightSize === 42 || +heightSize === 50 ){
heightSize = 285;
}
doc.addImage(img,'JPEG',5,8,200, +heightSize);
I hope it is helpful for you :)
var element = document.getElementById('inner');
var opt = {
margin: 30,
filename: this.auth_user,
image: {type: 'jpeg',quality: 0.98},
html2canvas: {
scale: 2,
bottom: 20
},
pagebreak: { mode: ['css'], padding : 200 },
jsPDF: {
unit: 'mm',
orientation: 'portrait'
}
};
html2pdf().set(opt).from(element).then(function() {
}).save();
Had also problems with overlapping text with safari browser. This fix helped: GitHub. "remove linebreaks from tags"
example
I want my maximum step count to cap at a dynamic integer. In this case it's 4. I went through the documentation but can't find anything that suits my needs. Does someone have an idea about this?
Ideally; I want the white space shown in red gone.
xAxis: {
min: 1.1,
ordinal: false,
max: 2,
labels: {
formatter: function () {
return 'Lap ' + this.value;
},
},
},
http://jsfiddle.net/d54uae3s/4/
You can use breaks from the broken-axis Highcharts module:
function createBreaks() {
var breaks = [];
for (var i = 1; i < 8; i++) {
breaks.push({
from: i + 0.4,
to: i + 1.1,
breakSize: 0.1
})
}
return breaks;
}
var chart = Highcharts.chart({
...,
xAxis: {
...
breaks: createBreaks()
}
});
Live demo: http://jsfiddle.net/BlackLabel/sjLdfegp/
API Reference: https://api.highcharts.com/highstock/xAxis.breaks
I have a sliding bar that has different values throughout it depending on which part of the sliding bar is clicked on. The ranges in my javascript represent the values. I am trying to pass the value selected to an ajax script, but cannot figure out how to do this.
I have tried doing this:
var range_selected = $("#sliderInterval").this.ranges.val();
But I get this error for the line above ^^:
Uncaught TypeError: Cannot read property 'ranges' of undefined
What can I do to capture the range the user clicks on and send it through with my AJAX data?
<div id="sliderBar">
<div id="sliderInterval">
<span id="sliderIntervalBudget">BUDGET</span>
</div>
</div>
JS
$(function() {
var ranges = [{
lower: 500,
upper: 1000
}, {
lower: 1100,
upper: 2000
}, {
lower: 2100,
upper: 5000
}, {
lower: 5100,
upper: 10000
}, {
lower: 11000,
upper: 20000
}, {
lower: 21000,
upper: 50000
}, ];
var wslider = $("#sliderBar").width() / (ranges.length);
for (var i = 0; i < ranges.length; i++) {
var range = $('<div class="rangedot"><div class="intervalCircle"></div></div>');
var left = (100 / (ranges.length) * i);
rangeleft = "calc(" + left + "% - 2px)";
range.css({
left: rangeleft,
width: wslider
});
range.on("click", function(idx) {
return function() {
var sliderleft = wslider * idx;
$("#sliderInterval").animate({
left: sliderleft
});
$("#budgetAmount").text("$" + ranges[idx].lower.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + " - " + "$" + ranges[idx].upper.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","));
};
}(i));
$("#sliderBar").append(range);
$("#sliderInterval").css("width", wslider + "px");
}
//$("#sliderInterval").show().text("BUDGET");
$("#budgetAmount").show().text("$500 - $1,000");
});