jsPDF- html() new function has no feature to set margin to pdf page - jspdf

i am using jsPDF into vue cli application, but i am unable to find any solution to set the margins to the pdf page. all the text and images are getting overflowed on the pages.
i want to set all the four margins. the syntax to set margins given in the jsPDF documentation is also not working.
this is my function to generate and download pdf:
downloadpdf() {
var pdf = new jsPDF("p", "pt", "a4");
pdf.setFontSize("10");
pdf.setLineWidth("100");
pdf.setTextColor("darkblue");
// Printing text
var vuejsinformation = `JQuery is a lightweight, "write less, do more", JavaScript library.`;
pdf.text(vuejsinformation, 10, 10);
//pdf.save("Sample.pdf");
// Printing a complete div container who has class pdfrapper
pdf.html(window.jQuery(".pdfwrapper").get(0), {
callback: function (pdf) {
pdf.save("Sample.pdf");
},
x: 10,
y: 10,
});
},
how to set all the four margins ?

You can add an option var in the jspdf.html() method like this:
jspdf.html(src, {
margin: number,
html2canvas: {width: number, height: number, ...}
...
})
However there seems to be an issue where the margin is ignored when using this method see https://github.com/MrRio/jsPDF/issues/2924.
It will probably be fixed soon :).
Here's the documentation for the jspdf.html() method http://raw.githack.com/MrRio/jsPDF/master/docs/module-html.html

This example for jsPDF version 2.1.1 should give you an idea on how to setup the margins.
var pageWidth = 8.5,
lineHeight = 1.2,
margin = 0.5,
maxLineWidth = pageWidth - margin * 2,
fontSize = 24,
ptsPerInch = 72,
oneLineHeight = (fontSize * lineHeight) / ptsPerInch,
text =
"Two households, both alike in dignity,\n" +
"In fair Verona, where we lay our scene,\n" +
"From ancient grudge break to new mutiny,\n" +
"Where civil blood makes civil hands unclean.\n" +
"From forth the fatal loins of these two foes\n" +
"A pair of star-cross'd lovers take their life;\n" +
"Whole misadventured piteous overthrows\n" +
"Do with their death bury their parents' strife.\n" +
"The fearful passage of their death-mark'd love,\n" +
"And the continuance of their parents' rage,\n" +
// Notice that the following will be wrapped to two lines automatically!
"Which, but their children's end, nought could remove, Is now the two hours' traffic of our stage;\n" +
"The which if you with patient ears attend,\n" +
"What here shall miss, our toil shall strive to mend.",
doc = new jsPDF({
unit: "in",
lineHeight: lineHeight
}).setProperties({ title: "String Splitting" });
// splitTextToSize takes your string and turns it in to an array of strings,
// each of which can be displayed within the specified maxLineWidth.
var textLines = doc
.setFont("helvetica")
.setFontSize(fontSize)
.splitTextToSize(text, maxLineWidth);
// doc.text can now add those lines easily; otherwise, it would have run text off the screen!
doc.text(textLines, margin, margin + 2 * oneLineHeight);
// You can also calculate the height of the text very simply:
var textHeight = (textLines.length * fontSize * lineHeight) / ptsPerInch;
doc
.setFont("Helvetica", "bold")
.text(
"Text Height: " + textHeight + " inches",
margin,
margin + oneLineHeight
);

Related

jsPDF - practical example for a fit-to-width shopping cart HTML page?

I'm trying to implement jsPDF pdf saving in a Vue app and I'm finding it overwhelming and nearly impossible to affect any visual change in the output.
The current results are: gigantic text and huge images.
Is there a way to get it to respect any of my CSS, #mediap print or otherwise, particularly for div borders?
The docs are very deep so I'd love an example of how to take a div-based table-like layout—e.g. a shopping cart—and fit it to width. I'd also love tips on avoid content bleeding across page breaks.
I've tried doc.setFont, doc.setFontSize and other methods and nothing changes the output.
this.doc.html(document.getElementById("pdfList"), {
callback: function (doc) {
doc.save("Cycad Inventory");
},
x: 40,
y: 40,
});
exportPDF = () => {
const unit = "pt";
const size = "A4"; // Use A1, A2, A3 or A4
const orientation = "portrait"; // portrait or landscape
const marginLeft = 30;
const doc = new jsPDF(orientation, unit, size);
doc.setFontSize(14);
const title = "Report";
const headers = [["Time", "Source", "Destination", "Protocol", "Length"]];
const data = this.state.ipData.map(elt => [elt.time, elt.source, elt.destination, elt.protocol, elt.length]);
let content = {
startY: 50,
head: headers,
body: data,
}
doc.text(title, marginLeft, 40);
doc.autoTable(content);
doc.save(this.state.ipData.fileName);
}
This is a code I used in reactJS. I hope this will help you to do changes to your code. Here I have declared the height, width, font sizes margins.

Add content before and after table (jsPDF autotable)

i have a question to jsPDF autotable.
My Code:
$('#printBtn').on('click', function() {
var pdf = new jsPDF('p', 'pt', 'a4');
var res = pdf.autoTableHtmlToJson(document.getElementById("tablePrint"));
pdf.autoTable(res.columns, res.data, {
theme : 'plain',
styles: {
fontSize: 12
},
showHeader: 'never',
createdCell: function(cell, data) {
var tdElement = cell.raw;
if (tdElement.classList.contains('hrow')) {
cell.styles.fontStyle = 'bold';
}
}
});
pdf.save("test.pdf");
});
I want add Text before and after the Table from a div.
I have found this Code Snippet in jsPDF autotable examples:
var before = "text before";
pdf.text(before, 14, 30);
This code works good. I have insert that before pdf.autoTable(...});.
But i dont know what the number 14 and 30 for?
Then i have the code insert after the pdf.autoTable function call and the Text printed on the last page of pdf but on the top of the page, not on the end, why?
Sorry for my bad englisch.
Thanks for help.
If what you want is to add something before you must first move the table that you are adding with autotable, you achieve this by adding a startY: 150 attribute within doc.autotable:
pdf.autoTable(res.columns, res.data, {
theme : 'plain',
styles: {
fontSize: 12
},
startY: 150,
showHeader: 'never',
createdCell: function(cell, data) {
var tdElement = cell.raw;
if (tdElement.classList.contains('hrow')) {
cell.styles.fontStyle = 'bold';
}
}
});
150 is the value in pixels you want to move. Above this you can place the text you want with the code you placed.
var before = "text before";
pdf.text(before, 14, 30);
Now the values of 14 (Value in Y) and 30 (Value in Y) are the values that you want the text to move in pixels.
In order for you to add text after the table you must first obtain in which number of pixels your table ended and from there enter the text you want.
let finalY = pdf.previousAutoTable.finalY; //this gives you the value of the end-y-axis-position of the previous autotable.
pdf.text("Text to be shown relative to the table", 12, finalY + 10); //you use the variable and add the number of pixels you want it to move.
Here's my stab at an answer:
So this is your Autotable's function call:
var pdf = new jsPDF('p', 'pt', 'a4');
Since jsPDF Autotables is based on jsPDF, you'll have to go here:
pt is a unit of measurement called points, so 14 and 30 are points. At the first position, 14, moves elements left and right. The second position, 30, moves elements down and up. I'm guessing they're like pixels(px). Seems like you have to move your text to your desired locations by using points.
An idea that helped me is to placing a Table with no content on the position where you would like to add the new table.
autoTable(doc, {
body: [],
startY: finalY + bias
});

Disable spiral in word cloud and display all the words in highcharts

Highcharts introduced word cloud in version 6.
I was trying out and I faced few problems which were not documented
How to disable the spiral nature and layout it horizontally?
All the words are not being displayed. In the below screenshot, there are exactly 500 words. But I cannot see them.
Lot's of empty space on either side.
I have exactly 500 words in this word cloud. With minimum weight as 5 and adding one to each additional word. So weights ranges from 5 to 505.
I have tried doing this, but no use.
Highcharts.seriesTypes.wordcloud.prototype.deriveFontSize = function(relativeWeight) {
var maxFontSize = 48;
// Will return a fontSize between 0px and 25px.
let size = Math.floor(maxFontSize * relativeWeight);
return size < 8 ? 8 : size;
};
I have set the width to 100% but it is still not occupying the whole area
Updated Fiddle link
UPDATE
I disabled the spiral nature by writing my own placement strategy like below. Just a copy paste of Highcharts original example and disabling rotation
var getRandomPosition = function getRandomPosition(size) {
return Math.round((size * (Math.random() + 0.5)) / 2);
};
var randomPlacement = function randomPlacement(point, options) {
var field = options.field,
r = options.rotation;
return {
x: getRandomPosition(field.width) - (field.width / 2),
y: getRandomPosition(field.height) - (field.height / 2),
rotation: 0
};
}
Highcharts.seriesTypes.wordcloud.prototype.placementStrategy.randomHorizontal = randomPlacement;
I also set the margins. But it did not help
marginRight: 0,
marginLeft: 0
marginBottom: 0
Addressing to second and third
Second there are all words in the chart but some are in very small size difficult to see. Here I use deriveFont
Third you can use chart.margin to reduce space outer edge of the chart and the plot area
This demo shows how to deal with second and third
/*Object.keys(data).map(function(key) {
data[key].name=key
});// just for demo to show 500 words populating*/
Highcharts.seriesTypes.wordcloud.prototype.deriveFontSize = function(relativeWeight) {
var maxFontSize =10;
// Will return a fontSize between 0px and 25px.
let size = Math.floor(maxFontSize * relativeWeight);
return size < 8 ? 15 : size; //sets min size to be 15 if less than 8
};
Highcharts.chart('container', {
chart: {
"type": "wordcloud",
margin: [20, 0, 0, 0]
},
"series": [{
"data": data,
"placementStrategy": 'random'
}],
"title": {
"text": "WORD CLOUD"
}
});
Fiddle demo
Update
It is not showing all 500 words. It will show all words only when font size is very small.
Workaround for reducing the spaces on both sides of the plot (in this particular case):
You can use negative margins:
marginRight: -300,
marginLeft: -300
Live demo: http://jsfiddle.net/kkulig/eyuvcpLe/
The latest release from highcharts has fixed my issue. But there are still other issues in the issue tracker opened by me in the highcharts.
Track it here
https://github.com/highcharts/highcharts/issues/7241

How to align text in center using jspdf

How to align text center using jsPDF.
var doc = new jsPDF();
doc.text(40, 250, 'Hi How are you');
If you are using the latest version (1.1.135) the api has changed some for the text function. It now reads as:
API.text = function(text, x, y, flags, angle, align);
If you don't need to use the flags or angle though, you can simply use:
var doc = new jsPDF();
doc.text('Hi How are you', 40, 250, 'center');
Keep in mind that the center call uses the x parameter now as the center of the text string, and not the left most border as it does when rendering left aligned.
Link to source
Edit:
Alternately you can calculate the proper x offset to just use the text function normally like so:
var text = "Hi How are you",
xOffset = (doc.internal.pageSize.width / 2) - (doc.getStringUnitWidth(text) * doc.internal.getFontSize() / 2);
doc.text(text, xOffset, 250);
Angular 6.
Footer align to horizontally center
var doc = new jsPDF();
var pageHeight = doc.internal.pageSize.height || doc.internal.pageSize.getHeight();
var pageWidth = doc.internal.pageSize.width || doc.internal.pageSize.getWidth();
// FOOTER
let str = "Your footer text";
doc.setTextColor(100);
doc.setFontSize(10);
doc.text(str, pageWidth / 2, pageHeight - 10, {align: 'center'});
doc.save("example.pdf");
Above answers didn't work for me, I ended up doing the following to center the text
let textX = (doc.internal.pageSize.getWidth() - doc.getTextWidth(text))/2
doc.text(text, textX, textY);
this worked:
var xOffset = doc.internal.pageSize.width / 2
doc.text('hello world', xOffset, 8, {align: 'center'});
2022: this works assuming your page width is 210 (default A4).
doc.text("This is centred text.", 105, 80, null, null, "center");
Here's a link to their live demo per the README:
http://raw.githack.com/MrRio/jsPDF/master/index.html
2022: I'm finding that JSPDF is buggy. It took a while to figure out how to install the advertised 'runs in a browser' implementation for a PHP app instead of a JS front end framework. There's a line that's required window.jsPDF = window.jspdf.jsPDF; that isn't mentioned anywhere in the documentation, I had to go through a downloaded example piece by piece to find it. Now I'm finding that the center text function doesn't work. In 2 different local environments and a JSFiddle, on multiple browsers, it sends the text off the left side of the page when the align:center option is implemented. While the above solution works, it breaks down if text is longer than one line, which, incidentally, is another out of the box bug - the text runs out of the document instead of wrapping, and there is no wrap option. So, it seems after all these hours I'm out of luck and I'll have to go a different route. Plugin is not maintained and this should be noted in documentation. Recommend to not waste your time.
This works somewhat, but isn't precise, if you know please tell me why.
I calculate the width of my text in order to center it myself.
For this, I used the getTextDimensions() method on my jsPDF object
var pdf = new jsPDF({
orientation : 'p',
unit: 'px',
format: [500, 750],
putOnlyUsedFonts:true
});
var textDimensions = pdf.getTextDimensions('MyText');
You can now use textDimensions.w to get text-width and textDimensions.h for height
Then use this to center your text.
var textWidth = textDimensions.w;
pdf.text('MyText', (pdfWidth / 2) - (textWidth / 2), 100);
BUT: You need to know your PDF's width to do this.
I 'solved' this by defining height and width myself, but you can easily find height and width of common formats online.
Like A4: 210mm*297mm.
Just remember to set unit: 'mm' when creating your jsPDF.
var doc = new jsPDF();
// set midPage for variable use
var midPage = doc.internal.pageSize.getWidth()/2
// Default is 210 mm so default midway by value is 105
doc.setFontSize(40);
doc.text("Octonyan loves jsPDF", 105, 15, null, null, "center");
// Better to use a variable "midPage" (from above)
doc.setFontSize(30);
doc.text("Centered (USA), Centred (UK)", midPage , 30, null, null, "center");

Openlayers 3 Feature Label Background

we are using OpenLayers 3 and want to add labels to our features. To improve visibility, we also want to add a background to those labels.
I have looked at: http://openlayers.org/en/v3.4.0/examples/vector-labels.html
but could not find another solution than increasing the overdraw width. But this results in bumby backgrounds and seems to be more like a hack for my problem.
Sadly we are not able to use another layer for the labels, cause the feature has to be on the same level as the corresponding label so that you can alway see a feature with its label in case it is overlapping with another feature (not only labels overlapping the features).
So I wanted to ask if you know a way to set the background of a label without using overdraw or a separate layer?
Best regards and thanks in advance
Basti
Updated description:
We want to render cars on a map. These cars should have labels with a rectangular background (in a color we can change) for the text so the user can read them more easily. Furthermore should the label be on the same level as the corresponding car. The reason behind this is that if cars are overlapping each other the labels should too and there should alway be one car with its label on top. I hope this description makes things a little bit clearer.
I managed to solve a similar problem by using a SVG shape behind the Text element and fill-up the shape with color, to achieve the same result.
I had to resize the background shape to match the size of text element and it wasn't as straightforward as I was hoping for.
The main blocks were:
SVG items don't have background style, and fill attribute on text element would only change the text color not its background color. That's why I had to use another shape in the first place.
When a SVG element is used as the source of an image element, all the javascript code inside it is ignored for security reasons. Therefore, you can't dynamically check/change sizes.
Shapes and Paths inside the SVG element are not part of DOM, so you can't access or style them with JavaScript or CSS.
First thing I did was to use the following code -- that I found somewhere on Stackoverflow, to get the width of the rendered text in pixels:
/* Get the rendered size of a text, in pixels */
/* _text: "Blah blah" */
/* _fontStyle: "Normal 12px Arial" */
function getTextWidth ( _text, _fontStyle ) {
var canvas = undefined,
context = undefined,
metrics = undefined;
canvas = document.createElement( "canvas" )
context = canvas.getContext( "2d" );
context.font = _fontStyle;
metrics = context.measureText( _text );
return metrics.width;
}
Then I used it inside my other function which was generating the marker and its label:
...
labelFontStyle = "Normal 12px Arial";
labelWidth = getTextWidth( _text, labelFontStyle );
labelWidth = labelWidth + 10;
iconSVG = '<svg ' +
'version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ' +
'x="0px" y="0px" width="' + labelWidth + 'px" height="16px" ' +
'viewBox="0 0 ' + labelWidth + ' 16" enable-background="new 0 0 ' + labelWidth + ' 16" xml:space="preserve">'+
'<rect x="0" y="0" width="' + labelWidth + '" height="16" stroke="#000000" fill="#DEEFAE" stroke-width="2"></rect>' +
'<text x="5" y="13" fill="#000000" font-family="Arial" font-size="12" font-weight="normal">' + _text + '</text>' +
'</svg>';
imageElement = new Image();
imageElement.src = 'data:image/svg+xml,' + escape( iconSVG );
iconStyle = new ol.style.Style({
"image": new ol.style.Icon({
"img": imageElement,
"imgSize":[labelWidth, 66],
"anchor": [0.5, 0.5],
"offset": [0, -50]
})
});
feature = new ol.Feature({
"geometry": new ol.geom.Point(
ol.proj.fromLonLat( [_longitude, _latitude] )
)
});
feature.setStyle( iconStyle );
return feature;
This is my answer that I originally posted here

Resources