Im trying to print the current page numbers using this: https://github.com/MrRio/jsPDF/pull/260
But jsPDF renders a huge amount of blank pages and crashes :(
Without the footer, every thing works fine and I get a nice PDF with 27 pages, but without footers ofcause
Console errors:
my footer is:
<footer>
<div style='text-align:center;'>Page <span class="pageCounter"></span>/<span class="totalPages"></span></div>
</footer>
and heres my Jquery part:
var doc = new jsPDF();
var margins = {
top: 10,
left: 10,
right: 10,
bottom: 20,
width: 265
};
doc.setProperties({
title: 'Title',
subject: 'This is the subject',
author: 'Author Name',
keywords: 'generated, javascript, web 2.0, ajax',
creator: 'Creator Name'
});
length = doc.internal.getNumberOfPages()
doc.fromHTML(response, margins.left, margins.top,{
'width': margins.width // max width of content on PDF
},
function(){
doc.save('noter.pdf');
}, margins);
You can use this code :
var doc = jsPDF();
doc.addPage();
doc.addPage();
doc.addPage();
doc.addPage();
var pageCount = doc.internal.getNumberOfPages(); //Total Page Number
for(i = 0; i < pageCount; i++) {
doc.setPage(i);
let pageCurrent = doc.internal.getCurrentPageInfo().pageNumber; //Current Page
doc.setFontSize(12);
doc.text('page: ' + pageCurrent + '/' + pageCount, 10, doc.internal.pageSize.height - 10);
}
Very strange! but apparently, the footer needs to have a <p> tag to make it work, even though it isen´t like that in the example on the github page...
So I´ve changed
<footer>
<div style='text-align:center;'>Page <span class="pageCounter"></span>/<span class="totalPages"></span></div>
</footer>
to
<footer>
<div><p>Page <span class="pageCounter"></span>/<span class="totalPages"></span></p></div>
</footer>
and it works now
Related
Using Net MVC and Signaturepad, I´m taking a signature from users and generating a PNG by using this:
<canvas id="#("canvas" + flat.ID)" width="400" height="200" style="background-color: lightgrey;"></canvas>
<script type="text/javascript">
var canvas = document.querySelector("#("#canvas" + flat.ID)");
var signaturePad = new SignaturePad(canvas, {
backgroundColor: 'rgba(211,211,211, 1)',
penColor: 'rgb(0, 0, 0)'
});
</script>
I´m storing the signature in a database by using
<button class="btn btn-shadow btn-block btn-primary" onclick="saveSignature('#Url.Action("SaveSignature", "Home", new { Area = "AssemblyOrders" })', signaturePad.toDataURL(), '#flat.ID', '#ViewBag.AssemblyOrderID')">Speichern</button>
This does nothing but setting the value in database.
In database I find the generated string:
data:image/png;base64,iVBORw...
I´m loading the view and if the viewmodel has that string I´m displaying it as an image:
<img src="#flat.Signature" style="width: 100%; height: 200px;"/>
This is only showing the lightgrey background from signaturepad but not the handwritten signature.
Where is the problem?
edit: I also tried saving it to desktop, but this png is also only lightgrey without lines.
Problem were this lines of code:
var signaturePad = new SignaturePad(canvas, {
backgroundColor: 'rgba(211,211,211, 1)',
penColor: 'rgb(0, 0, 0)'
});
Because of multiple canvas, as you can see from <canvas id="#("canvas" + flat.ID)" ..., the var signaturePad existed multiple times. Thus always the last var was used.
I solved it like this:
var pads = {};
...
pads["#("#canvas" + flat.ID)"] = new SignaturePad(canvas, {
backgroundColor: 'rgba(211,211,211, 1)',
penColor: 'rgb(0, 0, 0)'
});
and
onclick="saveSignature('#Url.Action("SaveSignature", "Home", new { Area = "AssemblyOrders" })', pads['#("#canvas" + flat.ID)'].toDataURL(), '#flat.ID', '#ViewBag.AssemblyOrderID')"
I have added this jspdf script on my website to download pdf. However I get this error.
Uncaught TypeError: Cannot read property '1' of undefined
at f.renderParagraph (jspdf.min.js:202)
at f.setBlockBoundary (jspdf.min.js:202)
at k (jspdf.min.js:202)
at k (jspdf.min.js:202)
at k (jspdf.min.js:202)
at jspdf.min.js:202
at l (jspdf.min.js:202)
at Image.i.onerror.i.onload (jspdf.min.js:202)
This happens on certain pages while others work fine.I have added the code I am using below. I am not sure if it is anything to do with my code or the jspdf.
//Code I am using:
<script type="text/javascript">
function HTMLtoPDF(){
var pdf = new jsPDF('p', 'pt', 'letter');
source = $('#HTMLtoPDF')[0];
specialElementHandlers = {
'#bypassme': function(element, renderer){
return true
}
}
margins = {
top: 50,
left: 60,
right:60,
width: 545
};
pdf.fromHTML(
source // HTML string or DOM elem ref.
, margins.left // x coord
, margins.top // y coord
, {
'width': margins.width // max width of content on PDF
, 'elementHandlers': specialElementHandlers
},
function (dispose) {
// dispose: object with X, Y of the last line add to the PDF
// this allow the insertion of new lines after html
pdf.save('Download.pdf');
}
)
}
</script>
<button type="button" onclick="HTMLtoPDF()" style=" height: 40px; width: 154px; background-color: #008800; color: #ffffff; font-size: 150%;">Download PDF </button>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js"> </script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.2/jspdf.min.js"></script>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
var str_pdf = $("#HTMLtoPDF").html();
var regex = /<br\s*[\/]?>/gi;
$("#HTMLtoPDF").html(str_pdf.replace(regex, '<p data-empty="true"><br></p>'));
});
function HTMLtoPDF(){
var pdf = new jsPDF('p', 'pt', 'a4');
source = $('#HTMLtoPDF')[0];
specialElementHandlers = {
'#bypassme': function (element, renderer) {
return true
}
};
margins = {
top: 30,
bottom: 30,
left: 40,
width: 522
};
pdf.fromHTML(
source,
margins.left,
margins.top, {
'width': margins.width,
'elementHandlers': specialElementHandlers
},
function (dispose) {
pdf.save('Download.pdf');
}, margins);
}
</script>
<!-- these js files are used for making PDF -->
I am using react-typescript and I have successfully created a PDF file from an html page with the help of this ref
Generating a PDF file from React Components
But if we want to create a PDF with multiple pages then what to do?
with a4 size page with appropriate margins at all sides and in each new page that margin should be applied.
And here is my code.
private printDocument() {
const input = document.getElementById("pdf");
html2canvas(input)
.then((canvas) => {
const pdf = new jsPDF("p", "px", "a4");
pdf.addHTML(input, 0, 0, {
pagesplit: true,
background: "#ffffff",
}, () => {
pdf.save("download.pdf");
});
});
}
please help me its argent.
Thank you in advance
I tried to use jsPDF to workaround this problem, but i did not succeed. The way that jsPDF manage the content to split in paged are not clear to me.
So i decided to use pdfMake, another amazing js library.
I got these infos in this question: Generating PDF files with JavaScript
In the question that you metioned (Generating a PDF file from React Components), the best answer sugest a good way to handle the pagination. You make a div for each page. But in my case, my content can dinamically increase your vertical size, so i can't fix the div's vertical sizes.
So, i did like this:
printDocument() {
const divs = document.getElementsByClassName('example');
const newList = [].slice.call(inputs);
var contentArray = []
var docDefinition = {
pageSize: {width: 800, height: 1173},
content: [
{
text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Confectum ponit legam, perferendis nomine miserum, animi. Moveat nesciunt triari naturam.'
}
]
}
Promise.map(newList, async (element, index) => {
let canvas = await html2canvas(element);
const imgData = await canvas.toDataURL('image/png');
// console.log("imgData URL => ", imgData)
// margin horizontal -40 = removing white spaces
return contentArray[`${index}`] = [{ image: imgData, width: canvas.width, height: canvas.height, margin: [-40, 0] }, {
text: ` ${index} - Lorem ipsum dolor sit amet, consectetur adipisicing elit. Confectum ponit legam, perferendis nomine miserum, animi.`
}];
}).then(
() => ( docDefinition.content.push(contentArray))
).then(
() => {
console.log("... starting download ...")
pdfMake.createPdf(docDefinition).download('examplePdf.pdf')
}
)
}
// In your react's component constructor ...
constructor(props) {
super(props);
this.printDocument = this.printDocument.bind(this)
}
// the imports below ...
import Promise from 'bluebird';
import html2canvas from 'html2canvas';
import pdfMake from 'pdfmake/build/pdfmake.js';
import pdfFonts from "pdfmake/build/vfs_fonts.js";
pdfMake.vfs = pdfFonts.pdfMake.vfs;
// i'm using these middlewares
import promise from 'redux-promise'
import multi from 'redux-multi'
import thunk from 'redux-thunk'
<div>
The approach here is: a div it's not a page. Because if the image generated by the canvas element it's bigger than the page vertical size, we'll need to control the pagination by ourselves. So, we broke our content in small elements to the pdf generator handle the pagination to us. This way we garantee that the pagination will occurs without cuts.
<div className="example" style={{ backgroundColor: '#ffffff', maxWidth: '800px', maxHeight: '1173px', borderStyle: 'groove', borderColor: 'red', margin: '0px' }} >
// any content or component here, we need maxHeight to be sure that the div's height size it's not bigger than the your PDF doc's height dimension, else your div may never be rendered inside it.
</div>
<div className="example" style={{ backgroundColor: '#ffffff', maxWidth: '800px', maxHeight: '1173px', borderStyle: 'groove', borderColor: 'red', margin: '0px' }} >
// any content or component here, we need maxHeight to be sure that the div's height size it's not bigger than the your PDF doc's height dimension, else your div may never be rendered inside it.
</div>
<div className="example" style={{ backgroundColor: '#ffffff', maxWidth: '800px', maxHeight: '1173px', borderStyle: 'groove', borderColor: 'red', margin: '0px' }} >
// any content or component here, we need maxHeight to be sure that the div's height size it's not bigger than the your PDF doc's height dimension, else your div may never be rendered inside it.
</div>
</div>
<div>
<button onClick={this.printDocument}> print using PDFMake </button>
</div>
Using the Promise.map by bluebird with the async/await resources, we can ensure that we'll wait till the end of generation of all images from canvas. This process can take a while depending of your image's size.
http://bluebirdjs.com/docs/api/promise.map.html
Take a look at pdfMake's github:
https://github.com/bpampuch/pdfmake
And his playground with excelent examples and how tos:
http://pdfmake.org/playground.html
I'll still trying to upgrade this way to solve this problem with the pagination, but it was the quickest way that i solved the problem and i hope to be useful for somebody.
Are you try?
const printDocument= () => {
const input = document.getElementById('divToPrint');
const input2 = document.getElementById('divToPrint2');
const pdf = new jsPDF();
html2canvas(input)
.then((canvas) => {
const imgData = canvas.toDataURL('image/png');
pdf.addImage(imgData, 'JPEG', 0, 0);
pdf.addPage();
html2canvas(input2)
.then((canvas2) => {
const imgData2 = canvas2.toDataURL('image/png');
pdf.addImage(imgData2, 'JPEG', 0, 0);
pdf.save("download.pdf");
})
;
})
;
}
probably nobody is there on a friday of a long weekend to answer this...
Working with jquery mobile beta and jquery mobile Scrollview
plugin.
There are 5 divs which are renedred by the scrtollview plugin and they are successfully drawn in a carousel manner with 5 divs side by side...
<div class="scrollme" data-scroll="x">
<div class="indDiv"> one
</div>
<div class="indDiv"> two
</div>
<div class="indDiv"> three
</div>
<div class="indDiv"> four
</div>
<div class="indDiv"> five
</div>
</div>
$('div.indDiv').bind('tap', function(e){
var clickedDiv = $(this);
// snap clickedDiv to the middle of the page
});
I have this requirement that when I tap on a div inside this carousel, i would want to move the corousel programattically so that the tapped div is snaped to the middle of the screen. I do not see a way to do with the scrollview plugin methods... I am flexible to switch to another plugin too...
anybody??
Thanks
Mostly, this involves appending something to the end of the document body due to position:relative/absolute issues.
I've written a simple plugin that allows centering and shading... It might not be production quality, but I've been happy with it for a while.
(function($) {
$.fn.center = function() {
this.css("position", "absolute");
this.css("top", (($(window).height() * .4) - this.height()) / 2
+ $(window).scrollTop() + "px");
this.css("left", ($(window).width() - this.width()) / 2
+ $(window).scrollLeft() + "px");
return this;
}
var shade = 0;
$.fn.unshade = function() {
$('.shade:last').remove();
var $children = $('.shade-front:last').children();
$children.each(function(k, v) {
if ($.data(v, 'shade-replace-previous').size() != 0) {
$.data(v, 'shade-replace-previous').append(v);
} else {
$.data(v, 'shade-replace-parent').prepend(v);
}
});
$('.shade-front:last').remove();
return $children;
}
$.fn.shade = function(css) {
var $shade = $('<div class="shade"/>');
$shade.css( {
position : "absolute",
width : '100%',
height : '100%',
top : 0,
left : 0,
background : "#000",
opacity : .7
})
$shade.click(function() {
$(this).unshade();
})
$('body').append($shade);
// Record our element's last position
this.each(function(k, v) {
var $this = $(v);
var prev = $this.prev();
var par = $this.parent();
$.data(v, 'shade-replace-previous', prev);
$.data(v, 'shade-replace-parent', par);
});
// Add them to the shadefront
var $shade_front = $('<div class="shade-front"/>');
$shade_front.css("background", "#FFF");
$shade_front.css("margin", "auto");
$shade_front.css("text-align", "center");
if (css) {
$shade_front.css(css);
}
$shade_front.append(this);
$shade_front.center();
$('body').append($shade_front);
return $shade_front;
}
})(jQuery);
I am using this plugin and then binding the swiperight/left to the next/prev buttons.
https://github.com/Wilto/Dynamic-Carousel
I have designed a jQuery Slider Control that takes a 'pool' of points, and allows them to be distributed between multiple sliders. It works pretty well, except that I am having some problems with very small overflow increments.
Basically, it is possible to make adjustments in large quantities based on mouse movement, and so it lets someone 'spend' more in a slider than intended. I am at a loss as to how to deal with this. Posted below is my entire code.
To test it, build a simple HTML page with this code and try sliding the first two sliders all the way to 500, then try sliding the third. It won't slide (intended behavior).
Then, slide the first or second slider back a little bit (subtracting), and slide the third forward. You are able to occasionally go over the intended 'spendable' bounds.
Sample will require jQuery UI, latest version from google CDN.
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.5/jquery-ui.js"></script>
Javascript
<style type="text/css">
#eq > div {
width:300px;
}
#eq > div .slider {
width: 200px; float: left;
}
#eq > div > span {
float: right;
}
</style>
<script type="text/javascript">
$(document).ready(function () {
var spendable = 1000;
var spent = 0;
function spend(quantity) {
spent += quantity;
$('#attemptedToSpend').text(spent);
}
function change(previous, current) {
var adjustment = (current - previous);
$('#change').text(adjustment);
return adjustment;
}
function calculateSpent() {
var totalled = 0;
$("#eq .slider").each(function () {
totalled += parseInt($(this).parent('div:eq(0)').find('.spent').text());
});
$('#spent').text(totalled);
}
$("#eq .slider").each(function () {
var current = 0;
var previous = 0;
var adjustment = 0;
$(this).slider({
range: "min",
value: 0,
min: 0,
max: 500,
step: 1,
animate: true,
orientation: "horizontal",
start: function (event, ui) {
},
stop: function (event, ui) {
},
slide: function (event, ui) {
// set the current value to whatever is selected.
current = ui.value;
// determine the adjustment being made relative to the last
// adjustment, instead of just the slider's value.
adjustment = change(previous, current);
if (spent >= spendable) {
if (adjustment > 0)
return false;
}
// spend the points, if we are able to.
spend(adjustment);
// set the previous value
previous = current;
$(this).parent('div:eq(0)').find('.spent').text(current);
calculateSpent();
}
});
});
});
</script>
Html
<p class="ui-state-default ui-corner-all" style="padding: 4px; margin-top: 4em;">
<span style="float: left; margin: -2px 5px 0 0;"></span>Distribution
</p>
<strong>Total Points Spendable: </strong><div id="spendable">1000</div>
<strong>Total Points Spent (Attempted): </strong><div id="attemptedToSpend">0</div>
<strong>Total Points Spent: </strong><div id="spent">0</div>
<strong>Change: </strong><div id="change">0</div>
<div id="status"></div>
<div id="eq">
<div style="margin: 15px;" id="test1">Test1</div>
<br />
<div class="slider"></div><span class="spent">0</span>
<div style="margin: 15px;" id="test2">Test2</div>
<br />
<div class="slider"></div><span class="spent">0</span>
<div style="margin: 15px;" id="test3">Test3</div>
<br />
<div class="slider"></div><span class="spent">0</span>
<div style="margin: 15px;" id="test4">Test4</div>
<br />
<div class="slider"></div><span class="spent">0</span>
<div style="margin: 15px;" id="test5">Test5</div>
<br />
<div class="slider"></div><span class="spent">0</span>
</div>
I tried keeping your script intact, but ended up largely rewriting it. It should be solid now. Good news: I have only changed the JS, everything else is intact, though I don't update all your monitoring fields any more.
DEMO
$(
function()
{
var
maxValueSlider = 500,
maxValueTotal = 1000,
$sliders = $("#eq .slider"),
valueSliders = [],
$displaySpentTotal = $('#spent');
function arraySum(arr)
{
var sum = 0, i;
for(i in arr) sum += arr[i];
return sum;
}
$sliders
.each(
function(i, slider)
{
var
$slider = $(slider),
$spent = $slider.next('.spent');
valueSliders[i] = 0;
$slider
.slider(
{
range: 'min',
value: 0,
min: 0,
max: maxValueSlider,
step: 1,
animate: true,
orientation: "horizontal",
slide:
function(event, ui)
{
var
sumRemainder = arraySum(valueSliders) - valueSliders[i],
adjustedValue = Math.min(maxValueTotal - sumRemainder, ui.value);
valueSliders[i] = adjustedValue;
// display the current total
$displaySpentTotal.text(sumRemainder + adjustedValue);
// display the current value
$spent.text(adjustedValue);
// set slider to adjusted value
$slider.slider('value', adjustedValue);
// stop sliding (return false) if value actually required adjustment
return adjustedValue == ui.value;
}
}
);
}
);
}
);