From 2b4b6e88804f241e278f2e05d26c2fdd94664c62 Mon Sep 17 00:00:00 2001 From: flyskyko Date: Thu, 22 Apr 2021 12:21:03 +0900 Subject: [PATCH] add context2d setLineDash() and lineDashOffset. --- src/jspdf.js | 2 +- src/libs/FileSaver.js | 3 +- src/libs/pdfname.js | 7 +++- src/modules/cell.js | 5 ++- src/modules/context2d.js | 68 ++++++++++++++++++++++++++++++++++ test/reference/lineDash.pdf | Bin 0 -> 3879 bytes test/specs/context2d.spec.js | 70 +++++++++++++++++++++++++++++++++++ 7 files changed, 150 insertions(+), 5 deletions(-) create mode 100644 test/reference/lineDash.pdf diff --git a/src/jspdf.js b/src/jspdf.js index 9820d1f0f..5cbea677b 100644 --- a/src/jspdf.js +++ b/src/jspdf.js @@ -2001,7 +2001,7 @@ function jsPDF(options) { font: font, out: out, newObject: newObject, - putStream: putStream, + putStream: putStream }); if (font.isAlreadyPutted !== true) { diff --git a/src/libs/FileSaver.js b/src/libs/FileSaver.js index ad1d302d1..89586ea36 100644 --- a/src/libs/FileSaver.js +++ b/src/libs/FileSaver.js @@ -90,7 +90,8 @@ var saveAs = /* noop */ } : // Use download attribute first if possible (#193 Lumia mobile) unless this is a native app - (typeof HTMLAnchorElement !== "undefined" && "download" in HTMLAnchorElement.prototype) + typeof HTMLAnchorElement !== "undefined" && + "download" in HTMLAnchorElement.prototype ? function saveAs(blob, name, opts) { var URL = _global.URL || _global.webkitURL; var a = document.createElement("a"); diff --git a/src/libs/pdfname.js b/src/libs/pdfname.js index 8b6b3e6ca..9987d35f8 100644 --- a/src/libs/pdfname.js +++ b/src/libs/pdfname.js @@ -5,8 +5,11 @@ */ function toPDFName(str) { // eslint-disable-next-line no-control-regex - if(/[^\u0000-\u00ff]/.test(str)){ // non ascii string - throw new Error('Invalid PDF Name Object: ' + str + ', Only accept ASCII characters.'); + if (/[^\u0000-\u00ff]/.test(str)) { + // non ascii string + throw new Error( + "Invalid PDF Name Object: " + str + ", Only accept ASCII characters." + ); } var result = "", strLength = str.length; diff --git a/src/modules/cell.js b/src/modules/cell.js index 1c69dbaa8..fce190739 100644 --- a/src/modules/cell.js +++ b/src/modules/cell.js @@ -442,7 +442,10 @@ import { jsPDF } from "../jspdf.js"; }); } - if (autoSize || (Array.isArray(headers) && typeof headers[0] === "string")) { + if ( + autoSize || + (Array.isArray(headers) && typeof headers[0] === "string") + ) { var headerName; for (i = 0; i < headerNames.length; i += 1) { headerName = headerNames[i]; diff --git a/src/modules/context2d.js b/src/modules/context2d.js index eb7edee14..fdba25141 100644 --- a/src/modules/context2d.js +++ b/src/modules/context2d.js @@ -51,6 +51,8 @@ import { this.currentPoint = ctx.currentPoint || new Point(); this.miterLimit = ctx.miterLimit || 10.0; this.lastPoint = ctx.lastPoint || new Point(); + this.lineDashOffset = ctx.lineDashOffset || 0.0; + this.lineDash = ctx.lineDash || []; this.ignoreClearRect = typeof ctx.ignoreClearRect === "boolean" ? ctx.ignoreClearRect : true; @@ -641,6 +643,32 @@ import { } }); + /** + * A float specifying the amount of the line dash offset. The default value is 0.0. + * + * @name lineDashOffset + * @default 0.0 + */ + Object.defineProperty(this, "lineDashOffset", { + get: function() { + return this.ctx.lineDashOffset; + }, + set: function(value) { + this.ctx.lineDashOffset = value; + setLineDash.call(this); + } + }); + + Object.defineProperty(this, "lineDash", { + get: function() { + return this.ctx.lineDash; + }, + set: function(value) { + this.ctx.lineDash = value; + setLineDash.call(this); + } + }); + // Not HTML API Object.defineProperty(this, "ignoreClearRect", { get: function() { @@ -652,6 +680,16 @@ import { }); }; + /** + * Sets the line dash pattern used when stroking lines. + * @name setLineDash + * @function + * @description It uses an array of values that specify alternating lengths of lines and gaps which describe the pattern. + */ + Context2D.prototype.setLineDash = function(dashArray) { + this.lineDash = dashArray; + }; + Context2D.prototype.fill = function() { pathPreProcess.call(this, "fill", false); }; @@ -1105,6 +1143,8 @@ import { this.lineCap = this.ctx.lineCap; this.lineWidth = this.ctx.lineWidth; this.lineJoin = this.ctx.lineJoin; + this.lineDash = this.ctx.lineDash; + this.lineDashOffset = this.ctx.lineDashOffset; } }; @@ -2383,4 +2423,32 @@ import { Math.round(maxy - miny) ); }; + + var getPrevLineDashValue = function(lineDash, lineDashOffset) { + return JSON.stringify({ + lineDash: lineDash, + lineDashOffset: lineDashOffset + }); + }; + + var setLineDash = function() { + // Avoid unnecessary line dash declarations. + if ( + !this.prevLineDash && + !this.ctx.lineDash.length && + !this.ctx.lineDashOffset + ) { + return; + } + + // Avoid unnecessary line dash declarations. + const nextLineDash = getPrevLineDashValue( + this.ctx.lineDash, + this.ctx.lineDashOffset + ); + if (this.prevLineDash !== nextLineDash) { + this.pdf.setLineDash(this.ctx.lineDash, this.ctx.lineDashOffset); + this.prevLineDash = nextLineDash; + } + }; })(jsPDF.API); diff --git a/test/reference/lineDash.pdf b/test/reference/lineDash.pdf new file mode 100644 index 0000000000000000000000000000000000000000..06342dc30fa37456190d7b75579b6fdd9e7b100d GIT binary patch literal 3879 zcmcH++iu!e@cn$nyhLqP1)p<#WrZR&P+EEsDMZ@UqC6Nlp^l85*oWPu-_$SY&vZX! zXKVuon@g(z$c$&kGjrzdv#U<`Tr^B}_T%UG|Ck9J;_)48wT$bhdj-aoKT`~^iHbA` zqz;%dP-(nKCMpG)BR;EX;9tg%Fye@?n|4FG&GpBXE_jw`c-|V<^c?Gk8SOaIC^-cy zlXP*xR5T?6=sq`u8J|=%(_c}9#gHM@iSp-+Hzem=+VC&q@Q&FH1hR|d4e(@D8_XF# zv4a+}VgB?38wq4WAvb{k)6y;BrzIVHkB&OpO2_C1a#;v$%5=TmGHYpTnMYdfI(szK z(N-GJGrR4siSE+hZXInU^$P})oPfV%M({ff=ZDsE`G&nYH2G~Sad~M73D{jUg-lVGd>2>6h_n~29TBS zg4zO=W$~cBdXNClaj7vXN1cC8hh5slWOnhbx7h|1u8R|8H8E>OWJPo257=H%Q zn_OL@aclC=SddpNwIQ=u>OPq^hiDOo=v(6bopp{A7bGbN%<%V)5)qbM0j4@3v+1c6Ke)oSZQ~YZH literal 0 HcmV?d00001 diff --git a/test/specs/context2d.spec.js b/test/specs/context2d.spec.js index 669f5af17..009663698 100644 --- a/test/specs/context2d.spec.js +++ b/test/specs/context2d.spec.js @@ -485,6 +485,76 @@ describe("Context2D: standard tests", () => { comparePdf(doc.output(), "moveTo_lineTo_stroke_fill.pdf", "context2d"); }); + it("context2d: setLineDash(), lineDashOffset", () => { + var doc = new jsPDF("p", "pt", "a4"); + var ctx = doc.context2d; + + var y = 20; + var pad = 20; + + ctx.lineWidth = 5; + ctx.beginPath(); + ctx.moveTo(20, y); + ctx.lineTo(200, y); + ctx.stroke(); + y += pad; + ctx.save(); + ctx.beginPath(); + ctx.setLineDash([10, 20]); + ctx.lineDashOffset = 10; + ctx.moveTo(20, y); + ctx.lineTo(200, y); + ctx.stroke(); + y += pad; + ctx.beginPath(); + ctx.setLineDash([]); + ctx.lineDashOffset = 0; + ctx.moveTo(20, y); + ctx.lineTo(200, y); + ctx.stroke(); + y += pad; + ctx.beginPath(); + ctx.setLineDash([10, 20]); + ctx.lineDashOffset = 10; + ctx.moveTo(20, y); + ctx.lineTo(200, y); + ctx.stroke(); + y += pad; + ctx.save(); + ctx.beginPath(); + ctx.setLineDash([]); + ctx.lineDashOffset = 0; + ctx.moveTo(20, y); + ctx.lineTo(200, y); + ctx.stroke(); + y += pad; + ctx.restore(); + ctx.beginPath(); + ctx.moveTo(20, y); + ctx.lineTo(200, y); + ctx.stroke(); + y += pad; + ctx.save(); + ctx.beginPath(); + ctx.moveTo(20, y); + ctx.lineTo(200, y); + ctx.stroke(); + y += pad; + ctx.restore(); + ctx.beginPath(); + ctx.moveTo(20, y); + ctx.lineTo(200, y); + ctx.stroke(); + y += pad; + ctx.restore(); + ctx.beginPath(); + ctx.moveTo(20, y); + ctx.lineTo(200, y); + ctx.stroke(); + + comparePdf(doc.output(), "lineDash.pdf", "context2d"); + }); + it("context2d: textBaseline", () => { var doc = new jsPDF({ orientation: "p",