Skip to content

Commit

Permalink
Merge branch 'featue/onward-jspdf'
Browse files Browse the repository at this point in the history
* featue/onward-jspdf:
  UPDATE webpack and webpack-dev-server
  UPDATE go for jspdf in version 2.5.1
  • Loading branch information
AndreKelling committed Jun 7, 2022
2 parents 12fc291 + 83a0425 commit 6a98d51
Show file tree
Hide file tree
Showing 29 changed files with 3,603 additions and 1,815 deletions.
13 changes: 13 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Editor configuration, see https://editorconfig.org
root = true

[*]
charset = utf-8
indent_style = tab
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
max_line_length = off
trim_trailing_whitespace = false
486 changes: 415 additions & 71 deletions docs/bundle.js

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions docs/vendors-node_modules_dompurify_dist_purify_js.bundle.js

Large diffs are not rendered by default.

Large diffs are not rendered by default.

1,677 changes: 1,677 additions & 0 deletions docs/vendors-node_modules_jspdf_node_modules_canvg_lib_index_es_js.bundle.js

Large diffs are not rendered by default.

2,597 changes: 1,139 additions & 1,458 deletions package-lock.json

Large diffs are not rendered by default.

18 changes: 10 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
{
"name": "jspdf-template",
"version": "3.1.1",
"main": "app.js",
"version": "4.0.0",
"main": "src/app.js",
"author": "André Kelling",
"description": "Invoice template and setup for jsPDF usage in ES6.",
"repository": "https://github.com/AndreKelling/jspdf-template",
"license": "MIT",
"scripts": {
"start": "webpack",
"webpack": "webpack-dev-server"
"build": "webpack --mode=development",
"dev": "webpack-dev-server --mode=development"
},
"dependencies": {
"jspdf-yworks": "^2.1.1",
"svg2pdf.js": "^1.5.0",
"webpack": "^5.72.0",
"jspdf": "^2.5.1",
"svg2pdf.js": "^2.2.0"
},
"devDependencies": {
"webpack": "^5.73.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.8.1"
"webpack-dev-server": "^4.9.2"
}
}
33 changes: 20 additions & 13 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,39 @@
# jsPDF Template

This a styled invoice Template [jsPDF](https://github.com/MrRio/jsPDF) in a simple _ES6 webpack_ setup.
This a styled invoice Template [jsPDF](https://github.com/parallax/jsPDF) in an _ES6 / ECMAScript webpack_ setup.

Includes [svg2pdf](https://github.com/yWorks/svg2pdf.js) for better SVG support. Which is also the reason why [jsPDF-yworks](https://github.com/yWorks/jsPDF) package had to replace the original one.
Includes [svg2pdf](https://github.com/yWorks/svg2pdf.js) for better SVG support.

Here there is a [demo](https://andrekelling.github.io/jspdf-template/).

## Releases
## Install

For a bit simpler usage i would suggest to refer back to [Version 1.0](https://github.com/AndreKelling/jspdf-template/releases/tag/1.0) of this development. Which isn't using jspdf-yworks package and integrates graphics as simple base64.
1. `npm install`

## Setup dev env
## Build

1. `npm install`
2. `npm run webpack`
For demonstration a docs [github page](https://andrekelling.github.io/jspdf-template/) is build.

1. `npm run build`

Just stay on development mode. Doesn't need caching manifestation.

## Development

1. `npm run dev`

## Custom-Font file

I do use a custom font here. Which is prepared as base64 code like following: https://github.com/MrRio/jsPDF/#use-of-utf-8--ttf
I do use a custom font here. Which is prepared as base64 code like following: https://github.com/parallax/jsPDF#use-of-unicode-characters--utf-8

1. My custom fonts are laying as .ttf font-files in `src/fonts` subdirectory.
2. prepared JS script with the font's base64 code are in `src/print/fonts`
3. they got a `import jsPDF from 'jspdf-yworks';` added at the very top
3. they got a `import { jsPDF } from 'jspdf';` added at the very top

## Description
## Structure

* Print components are placed in `src/print/pdf`
* `fetchSvg` and `newPage` are tools placed in `src/print`
* Print components or template partials are placed in `src/print/partials`
* `fetchSvg` and `newPage` are tools placed in `src/print/utils`

### Image sizes

Expand All @@ -38,5 +45,5 @@ Images need to be SVG in here!

## Issues

* the yworks fork of jsPDF is used for their proper SVG integration. Still SVG should be SVGO (eg. https://jakearchibald.github.io/svgomg/ or configure a SVGO export in sketch [sketch SVGO export plugin](https://www.sketch.com/extensions/plugins/svgo-compressor/) like this https://github.com/sketch-hq/svgo-compressor/issues/20#issuecomment-411478737) optimized. So some attributes not working for rendering are removed.
* SVG should be SVGO (eg. https://jakearchibald.github.io/svgomg/ or configure a SVGO export in sketch [sketch SVGO export plugin](https://www.sketch.com/extensions/plugins/svgo-compressor/) like this https://github.com/sketch-hq/svgo-compressor/issues/20#issuecomment-411478737) optimized. So some attributes not working for rendering are removed.
* currently using localStorage to save the background graphic globally for synchronous usage. Might not be the best idea.
2 changes: 1 addition & 1 deletion src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const basePrintData = {
},
'address': {
'company':'Johnlands',
'person':'John Jonaldo',
'person':'Jona Jonaldo',
'street':'Jonestreet 123',
'city':'12345 Jenese Joplin',
},
Expand Down
4 changes: 1 addition & 3 deletions src/fonts/WorkSans-bold.js

Large diffs are not rendered by default.

4 changes: 1 addition & 3 deletions src/fonts/WorkSans-normal.js

Large diffs are not rendered by default.

15 changes: 0 additions & 15 deletions src/print/fetchSvg.js

This file was deleted.

68 changes: 37 additions & 31 deletions src/print/index.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
//import jsPDF from '../../node_modules/jspdf-yworks/dist/jspdf.debug';
import jsPDF from 'jspdf-yworks';
import jsPDF from 'jspdf';
import addFontNormal from '../fonts/WorkSans-normal';
import addFontBold from '../fonts/WorkSans-bold';
import svg2pdf from 'svg2pdf.js';
import fetchSvg from './fetchSvg';
import addressSender from './pdf/addressSender';
import addressCustomer from './pdf/addressCustomer';
import heading from './pdf/heading';
import table from './pdf/table';
import totals from './pdf/totals';
import text from './pdf/text';
import footer from './pdf/footer';
import logo from './pdf/logo';
import 'svg2pdf.js';
import fetchSvg from './utils/fetchSvg';
import addressSender from './partials/addressSender';
import addressCustomer from './partials/addressCustomer';
import heading from './partials/heading';
import table from './partials/table';
import totals from './partials/totals';
import text from './partials/text';
import footer from './partials/footer';
import logo from './partials/logo';

export default (printData) => {
addFontNormal();
addFontBold();

const doc = new jsPDF('p', 'pt');
doc.vars = {};
doc.vars.fontFamily = 'WorkSans';
doc.vars.fontWeightBold = 'bold';
doc.vars.fontWeightNormal = 'normal';

doc.setFont('WorkSans');
doc.setFont(doc.vars.fontFamily);

// <><>><><>><>><><><><><>>><><<><><><><>
// SETTINGS
Expand All @@ -46,34 +50,36 @@ export default (printData) => {
// <><>><><>><>><><><><><>>><><<><><><><>
// Background init
// need to print the background before other elements get printed on
fetchSvg(doc, 'img/background.svg').then((svg) => {
fetchSvg('img/background.svg').then(async ({svg, width}) => {
if (svg) {
doc.setPage(1);

svg2pdf(svg, doc, {
xOffset: -70,
yOffset: 250
});

doc.vars.bgImageWidth = width;
doc.vars.bgImage = new XMLSerializer().serializeToString(svg);

localStorage.setItem('bgSvg', new XMLSerializer().serializeToString(svg));
await doc.svg(svg, {
x: pageCenterX - width / 2,
y: 250
});
}

// <><>><><>><>><><><><><>>><><<><><><><>
// Sender's address

startY = addressSender(doc, printData.addressSender, startY, fontSizes.NormalFontSize, lineSpacing);

const addressSvgLoaded = fetchSvg(doc, 'img/address-bar.svg').then((svg) => {
if (svg) {
doc.setPage(1);
const addressSvgLoaded = fetchSvg('img/address-bar.svg').then(({svg, width, height}) => {
doc.setPage(1);

svg2pdf(svg, doc, {
xOffset: 225,
yOffset: 136,
scale: 0.45 // scaling for finer details
});
}
const xOffset = 225;
const scale = 0.45; // scaling for finer details

doc.svg(svg, {
x: xOffset,
y: 136,
width: width * scale,
height: height * scale
});
});
// <><>><><>><>><><><><><>>><><<><><><><>
// Customer address
Expand All @@ -93,17 +99,17 @@ export default (printData) => {
// <><>><><>><>><><><><><>>><><<><><><><>
// Table with items

startY = table(doc, printData, startY, fontSizes.NormalFontSize, lineSpacing);
startY = await table(doc, printData, startY, fontSizes.NormalFontSize, lineSpacing);

// <><>><><>><>><><><><><>>><><<><><><><>
// Totals

startY = totals(doc, printData, startY, fontSizes.NormalFontSize, lineSpacing);
startY = await totals(doc, printData, startY, fontSizes.NormalFontSize, lineSpacing);

// <><>><><>><>><><><><><>>><><<><><><><>
// Text

startY = text(doc, printData.invoice.text, startY, fontSizes.NormalFontSize, lineSpacing);
startY = await text(doc, printData.invoice.text, startY, fontSizes.NormalFontSize, lineSpacing);

// <><>><><>><>><><><><><>>><><<><><><><>
// Footer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export default (doc, address, startY, fontSize, lineSpacing) => {
const startX = 57;

//-------Customer Info Address---------------------
doc.setFontType('bold');
doc.setFont(doc.vars.fontFamily, doc.vars.fontWeightBold);
doc.setFontSize(fontSize);

address = Object.values(address);
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ export default (doc, data, headline, startX, startY, lineSpacing) => {

const dataArr = Object.values(data);

doc.setFontType('bold');
doc.setFont(doc.vars.fontFamily, doc.vars.fontWeightBold);
doc.text(headline, startX + padding, tempY += lineSpacing);
tempY += lineSpacing;

doc.setFontType('normal');
doc.setFont(doc.vars.fontFamily, doc.vars.fontWeightNormal);
dataArr.map(text => {
if (text) {
doc.text(text, startX + padding, tempY += lineSpacing);
Expand Down
6 changes: 3 additions & 3 deletions src/print/pdf/heading.js → src/print/partials/heading.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ export default (doc, data, startY, fontSizes, lineSpacing) => {
const pageWidth = doc.internal.pageSize.width;
const endX = pageWidth - startX;

doc.setFontType('normal');
doc.setFont(doc.vars.fontFamily, doc.vars.fontWeightNormal);
doc.setFontSize(fontSizes.SubTitleFontSize);

// set fix value for Y to bring title in alignment with folding marks
startY = 243;
doc.text(invoiceNrTxt, startX, startY);

doc.setFontType('bold');
doc.setFont(doc.vars.fontFamily, doc.vars.fontWeightBold);

startX += doc.getStringUnitWidth(invoiceNrTxt) * fontSizes.SubTitleFontSize;
doc.text(data.invoice.number, startX, startY);

doc.setFontType('normal');
doc.setFont(doc.vars.fontFamily, doc.vars.fontWeightNormal);
const location = data.invoice.location ? data.invoice.location + ', ' : '';
doc.text(location + data.invoice.date, endX, startY, 'right');

Expand Down
26 changes: 26 additions & 0 deletions src/print/partials/logo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import fetchSvg from "../utils/fetchSvg";

export default (doc, printData, pageNr) => {
const pageWidth = doc.internal.pageSize.width;
const pageCenterX = pageWidth / 2;
let n;

return fetchSvg('img/logo.svg').then(async ({svg, width}) => {
if (svg) {
n = 0;

while (n < pageNr) {
n++;

doc.setPage(n);

await doc.svg(svg, {
x: pageCenterX - width / 2,
y: 25
});

doc.link(pageCenterX - width / 2, 25, width, 60, {url: printData.personalInfo.website});
}
}
});
}
72 changes: 72 additions & 0 deletions src/print/partials/table.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import newPage from '../utils/newPage';

export default async (doc, printData, startY, fontSize, lineSpacing) => {

let startX = 57;
const pageWidth = doc.internal.pageSize.width;
const endX = pageWidth - startX;

const tablecol2X = 386;
const tablecol3X = 460;

doc.setFontSize(fontSize);
doc.setFont(doc.vars.fontFamily, doc.vars.fontWeightNormal);

//-------Table Header---------------------
startY += lineSpacing * 1.5;

doc.text(printData.label.tableItems, startX, startY);
doc.text(printData.label.tableQty, tablecol2X, startY, {align: 'right'});
doc.text(printData.label.tableSinglePrice, tablecol3X, startY, {align: 'right'});
doc.text(printData.label.tableSingleTotal, endX, startY, {align: 'right'});

startY += lineSpacing;

doc.line(startX, startY, endX, startY);

startY += lineSpacing * 1.5;

//-------Table Body---------------------

const items = Object.values(printData.items);

for (const item of items) {
doc.setFont(doc.vars.fontFamily, doc.vars.fontWeightBold);
const splitTitle = doc.splitTextToSize(
item.title,
tablecol2X - startX - lineSpacing * 1.5
);
const heightTitle = splitTitle.length * doc.internal.getLineHeight();

doc.setFont(doc.vars.fontFamily, doc.vars.fontWeightNormal);
const splitDescription = doc.splitTextToSize(
item.description,
tablecol2X - startX - lineSpacing * 1.5
);
const heightDescription = splitDescription.length * doc.internal.getLineHeight();

// <><>><><>><>><><><><><>>><><<><><><><>
// new page check before item output
// @todo: display table header at start of a new page
startY = await newPage(doc, startY, heightDescription + heightTitle);

doc.setFont(doc.vars.fontFamily, doc.vars.fontWeightBold);
doc.text(splitTitle, startX, startY);

// tweak Y to be below title. fits nicer with long descriptions. descriptions will be probably taking a row space while titles do not.
startY += heightTitle;

doc.setFont(doc.vars.fontFamily, doc.vars.fontWeightNormal);
doc.text(splitDescription, startX, startY);

doc.text(item.qty, tablecol2X, startY, {align: 'right'});

doc.text(item.amount, tablecol3X, startY, {align: 'right'});

doc.text(item.total, endX, startY, {align: 'right'});

startY += heightDescription + lineSpacing;
}

return startY;
}
Loading

0 comments on commit 6a98d51

Please sign in to comment.