diff --git a/src/modules/html.js b/src/modules/html.js index 0c68e5ba1..fe46e9de0 100644 --- a/src/modules/html.js +++ b/src/modules/html.js @@ -320,11 +320,16 @@ import { globalObject } from "../libs/globalObject.js"; position: "relative", display: "inline-block", width: - Math.max( - this.prop.src.clientWidth, - this.prop.src.scrollWidth, - this.prop.src.offsetWidth - ) + "px", + (typeof this.opt.width === "number" && + !isNaN(this.opt.width) && + typeof this.opt.windowWidth === "number" && + !isNaN(this.opt.windowWidth) + ? this.opt.windowWidth + : Math.max( + this.prop.src.clientWidth, + this.prop.src.scrollWidth, + this.prop.src.offsetWidth + )) + "px", left: 0, right: 0, top: 0, @@ -429,11 +434,20 @@ import { globalObject } from "../libs/globalObject.js"; var pdf = this.opt.jsPDF; var fontFaces = this.opt.fontFaces; + + var scale = + typeof this.opt.width === "number" && + !isNaN(this.opt.width) && + typeof this.opt.windowWidth === "number" && + !isNaN(this.opt.windowWidth) + ? this.opt.width / this.opt.windowWidth + : 1; + var options = Object.assign( { async: true, allowTaint: true, - scale: 1, + scale: scale, scrollX: this.opt.scrollX || 0, scrollY: this.opt.scrollY || 0, backgroundColor: "#ffffff", @@ -1011,8 +1025,14 @@ import { globalObject } from "../libs/globalObject.js"; * @param {Html2CanvasOptions} [options.html2canvas] html2canvas options * @param {FontFace[]} [options.fontFaces] A list of font-faces to match when resolving fonts. Fonts will be added to the PDF based on the specified URL. If omitted, the font match algorithm falls back to old algorithm. * @param {jsPDF} [options.jsPDF] jsPDF instance - * @param {number} [options.x] x position on the PDF document - * @param {number} [options.y] y position on the PDF document + * @param {number=} [options.x] x position on the PDF document in jsPDF units. + * @param {number=} [options.y] y position on the PDF document in jsPDF units. + * @param {number=} [options.width] The target width in the PDF document in jsPDF units. The rendered element will be + * scaled such that it fits into the specified width. Has no effect if either the html2canvas.scale is + * specified or the windowWidth option is NOT specified. + * @param {number=} [options.windowWidth] The window width in CSS pixels. In contrast to the + * html2canvas.windowWidth option, this option affects the actual container size while rendering and + * does NOT affect CSS media queries. This option only has an effect, if the width option is also specified. * * @example * var doc = new jsPDF(); diff --git a/test/reference/html-width-100-windowWidth-500.pdf b/test/reference/html-width-100-windowWidth-500.pdf new file mode 100644 index 000000000..4fb42d34d Binary files /dev/null and b/test/reference/html-width-100-windowWidth-500.pdf differ diff --git a/test/reference/html-width-210-windowWidth-1000.pdf b/test/reference/html-width-210-windowWidth-1000.pdf new file mode 100644 index 000000000..c7704ddd0 Binary files /dev/null and b/test/reference/html-width-210-windowWidth-1000.pdf differ diff --git a/test/reference/html-width-210-windowWidth-250.pdf b/test/reference/html-width-210-windowWidth-250.pdf new file mode 100644 index 000000000..287db7ba9 Binary files /dev/null and b/test/reference/html-width-210-windowWidth-250.pdf differ diff --git a/test/reference/html-width-210-windowWidth-500.pdf b/test/reference/html-width-210-windowWidth-500.pdf new file mode 100644 index 000000000..228565a61 Binary files /dev/null and b/test/reference/html-width-210-windowWidth-500.pdf differ diff --git a/test/reference/html-width-300-windowWidth-500-scale-2.pdf b/test/reference/html-width-300-windowWidth-500-scale-2.pdf new file mode 100644 index 000000000..54058571e Binary files /dev/null and b/test/reference/html-width-300-windowWidth-500-scale-2.pdf differ diff --git a/test/reference/html-width-300-windowWidth-500.pdf b/test/reference/html-width-300-windowWidth-500.pdf new file mode 100644 index 000000000..3cdfc67a5 Binary files /dev/null and b/test/reference/html-width-300-windowWidth-500.pdf differ diff --git a/test/reference/html-width-default-windowWidth-default.pdf b/test/reference/html-width-default-windowWidth-default.pdf new file mode 100644 index 000000000..227caa0e0 Binary files /dev/null and b/test/reference/html-width-default-windowWidth-default.pdf differ diff --git a/test/specs/README.md b/test/specs/README.md index 114a739e4..8db5aca60 100644 --- a/test/specs/README.md +++ b/test/specs/README.md @@ -20,7 +20,7 @@ If a reference PDF doesn't exist it will be created if you run this command while the tests run: ``` -node tests/utils/reference-server.js +node test/utils/reference-server.js ``` This generates and collects reference PDFs from real browsers. This should be diff --git a/test/specs/html.spec.js b/test/specs/html.spec.js index 9ed99e8de..c5f8318ce 100644 --- a/test/specs/html.spec.js +++ b/test/specs/html.spec.js @@ -27,7 +27,7 @@ function toFontFaceRule(fontFace) { `; } -describe("Module: html", function() { +describe("Module: html", () => { if ( (typeof isNode != "undefined" && isNode) || navigator.userAgent.indexOf("Chrome") < 0 @@ -41,6 +41,89 @@ describe("Module: html", function() { comparePdf(doc.output(), "html-basic.pdf", "html"); }); + it("respects width and windowWidth options", async () => { + const markup = + "
" + + "Lorem ipsum dolor sit amet consectetur adipisicing elit. Eveniet reprehenderit nihil natus magnam doloremque voluptate ab, laborum officiis corrupti eius voluptatibus quisquam illum esse corporis quod fugit quibusdam minima provident." + + "
"; + + const doc210$250 = await render(markup, { width: 210, windowWidth: 250 }); + comparePdf( + doc210$250.output(), + "html-width-210-windowWidth-250.pdf", + "html" + ); + + const doc210$500 = await render(markup, { width: 210, windowWidth: 500 }); + comparePdf( + doc210$500.output(), + "html-width-210-windowWidth-500.pdf", + "html" + ); + + const doc210$1000 = await render(markup, { width: 210, windowWidth: 1000 }); + comparePdf( + doc210$1000.output(), + "html-width-210-windowWidth-1000.pdf", + "html" + ); + + const doc100$500 = await render(markup, { width: 100, windowWidth: 500 }); + comparePdf( + doc100$500.output(), + "html-width-100-windowWidth-500.pdf", + "html" + ); + + const doc300$500 = await render(markup, { width: 300, windowWidth: 500 }); + comparePdf( + doc300$500.output(), + "html-width-300-windowWidth-500.pdf", + "html" + ); + }); + + it("width should not overwrite user-provided html2canvas.scale option", async () => { + const markup = + "
" + + "Lorem ipsum dolor sit amet consectetur adipisicing elit. Eveniet reprehenderit nihil natus magnam doloremque voluptate ab, laborum officiis corrupti eius voluptatibus quisquam illum esse corporis quod fugit quibusdam minima provident." + + "
"; + const doc = await render(markup, { + width: 300, + windowWidth: 500, + html2canvas: { scale: 2 } + }); + comparePdf( + doc.output(), + "html-width-300-windowWidth-500-scale-2.pdf", + "html" + ); + }); + + it("width and windowWidth should only have an effect if both are supplied", async () => { + const markup = + "
" + + "Lorem ipsum dolor sit amet consectetur adipisicing elit. Eveniet reprehenderit nihil natus magnam doloremque voluptate ab, laborum officiis corrupti eius voluptatibus quisquam illum esse corporis quod fugit quibusdam minima provident." + + "
"; + const docWidthOnly = await render(markup, { + width: 300 + }); + comparePdf( + docWidthOnly.output(), + "html-width-default-windowWidth-default.pdf", + "html" + ); + + const docWindowWidthOnly = await render(markup, { + windowWidth: 500 + }); + comparePdf( + docWindowWidthOnly.output(), + "html-width-default-windowWidth-default.pdf", + "html" + ); + }); + it("renders font-faces", async () => { const opts = { fontFaces: [ diff --git a/types/index.d.ts b/types/index.d.ts index 02310ae91..d49d65811 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -229,6 +229,8 @@ declare module "jspdf" { jsPDF?: jsPDF; x?: number; y?: number; + width?: number; + windowWidth?: number; fontFaces?: HTMLFontFace[]; }