diff --git a/README.md b/README.md index 7e3565d3..99bde92f 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,11 @@ const signaturePad = new SignaturePad(canvas); signaturePad.toDataURL(); // save image as PNG signaturePad.toDataURL("image/jpeg"); // save image as JPEG signaturePad.toDataURL("image/jpeg", 0.5); // save image as JPEG with 0.5 image quality -signaturePad.toDataURL("image/svg+xml"); // save image as SVG +signaturePad.toDataURL("image/svg+xml"); // save image as SVG data url + +// Return svg string without converting to base64 +signaturePad.toSVG(); // "" +signaturePad.toSVG({includeBackgroundColor: true}); // add background color to svg output // Draws signature image from data URL (mostly uses https://mdn.io/drawImage under-the-hood) // NOTE: This method does not populate internal data structure that represents drawn signature. Thus, after using #fromDataURL, #toData won't work properly. diff --git a/docs/js/signature_pad.umd.js b/docs/js/signature_pad.umd.js index 5643612f..4b615d84 100644 --- a/docs/js/signature_pad.umd.js +++ b/docs/js/signature_pad.umd.js @@ -1,5 +1,5 @@ /*! - * Signature Pad v4.0.9 | https://github.com/szimek/signature_pad + * Signature Pad v4.0.10 | https://github.com/szimek/signature_pad * (c) 2022 Szymon Nowak | Released under the MIT license */ @@ -268,8 +268,14 @@ toDataURL(type = 'image/png', encoderOptions) { switch (type) { case 'image/svg+xml': - return this._toSVG(); + if (typeof encoderOptions !== 'object') { + encoderOptions = undefined; + } + return `data:image/svg+xml;base64,${btoa(this.toSVG(encoderOptions))}`; default: + if (typeof encoderOptions !== 'number') { + encoderOptions = undefined; + } return this.canvas.toDataURL(type, encoderOptions); } } @@ -499,7 +505,7 @@ } } } - _toSVG() { + toSVG({ includeBackgroundColor = false } = {}) { const pointGroups = this._data; const ratio = Math.max(window.devicePixelRatio || 1, 1); const minX = 0; @@ -507,8 +513,18 @@ const maxX = this.canvas.width / ratio; const maxY = this.canvas.height / ratio; const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - svg.setAttribute('width', this.canvas.width.toString()); - svg.setAttribute('height', this.canvas.height.toString()); + svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); + svg.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); + svg.setAttribute('viewBox', `${minX} ${minY} ${maxX} ${maxY}`); + svg.setAttribute('width', maxX.toString()); + svg.setAttribute('height', maxY.toString()); + if (includeBackgroundColor && this.backgroundColor) { + const rect = document.createElement('rect'); + rect.setAttribute('width', '100%'); + rect.setAttribute('height', '100%'); + rect.setAttribute('fill', this.backgroundColor); + svg.appendChild(rect); + } this._fromData(pointGroups, (curve, { penColor }) => { const path = document.createElement('path'); if (!isNaN(curve.control1.x) && @@ -535,27 +551,7 @@ circle.setAttribute('fill', penColor); svg.appendChild(circle); }); - const prefix = 'data:image/svg+xml;base64,'; - const header = ''; - let body = svg.innerHTML; - if (body === undefined) { - const dummy = document.createElement('dummy'); - const nodes = svg.childNodes; - dummy.innerHTML = ''; - for (let i = 0; i < nodes.length; i += 1) { - dummy.appendChild(nodes[i].cloneNode(true)); - } - body = dummy.innerHTML; - } - const footer = ''; - const data = header + body + footer; - return prefix + btoa(data); + return svg.outerHTML; } } diff --git a/src/signature_pad.ts b/src/signature_pad.ts index 1422a20d..f76a6440 100644 --- a/src/signature_pad.ts +++ b/src/signature_pad.ts @@ -26,6 +26,10 @@ export interface FromDataOptions { clear?: boolean; } +export interface ToSVGOptions { + includeBackgroundColor?: boolean; +} + export interface PointGroupOptions { dotSize: number; minWidth: number; @@ -138,11 +142,27 @@ export default class SignaturePad extends SignatureEventTarget { }); } - public toDataURL(type = 'image/png', encoderOptions?: number): string { + public toDataURL( + type: 'image/svg+xml', + encoderOptions?: ToSVGOptions, + ): string; + public toDataURL(type: string, encoderOptions?: number): string; + public toDataURL( + type = 'image/png', + encoderOptions?: number | ToSVGOptions | undefined, + ): string { switch (type) { case 'image/svg+xml': - return this._toSVG(); + if (typeof encoderOptions !== 'object') { + encoderOptions = undefined; + } + return `data:image/svg+xml;base64,${btoa( + this.toSVG(encoderOptions as ToSVGOptions), + )}`; default: + if (typeof encoderOptions !== 'number') { + encoderOptions = undefined; + } return this.canvas.toDataURL(type, encoderOptions); } } @@ -580,7 +600,7 @@ export default class SignaturePad extends SignatureEventTarget { } } - private _toSVG(): string { + public toSVG({ includeBackgroundColor = false }: ToSVGOptions = {}): string { const pointGroups = this._data; const ratio = Math.max(window.devicePixelRatio || 1, 1); const minX = 0; @@ -589,8 +609,20 @@ export default class SignaturePad extends SignatureEventTarget { const maxY = this.canvas.height / ratio; const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - svg.setAttribute('width', this.canvas.width.toString()); - svg.setAttribute('height', this.canvas.height.toString()); + svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); + svg.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); + svg.setAttribute('viewBox', `${minX} ${minY} ${maxX} ${maxY}`); + svg.setAttribute('width', maxX.toString()); + svg.setAttribute('height', maxY.toString()); + + if (includeBackgroundColor && this.backgroundColor) { + const rect = document.createElement('rect'); + rect.setAttribute('width', '100%'); + rect.setAttribute('height', '100%'); + rect.setAttribute('fill', this.backgroundColor); + + svg.appendChild(rect); + } this._fromData( pointGroups, @@ -638,34 +670,6 @@ export default class SignaturePad extends SignatureEventTarget { }, ); - const prefix = 'data:image/svg+xml;base64,'; - const header = - ''; - let body = svg.innerHTML; - - // IE hack for missing innerHTML property on SVGElement - if (body === undefined) { - const dummy = document.createElement('dummy'); - const nodes = svg.childNodes; - dummy.innerHTML = ''; - - // tslint:disable-next-line: prefer-for-of - for (let i = 0; i < nodes.length; i += 1) { - dummy.appendChild(nodes[i].cloneNode(true)); - } - - body = dummy.innerHTML; - } - - const footer = ''; - const data = header + body + footer; - - return prefix + btoa(data); + return svg.outerHTML; } } diff --git a/tests/__snapshots__/signature_pad.test.ts.snap b/tests/__snapshots__/signature_pad.test.ts.snap index 6c85d23d..9e8260f1 100644 --- a/tests/__snapshots__/signature_pad.test.ts.snap +++ b/tests/__snapshots__/signature_pad.test.ts.snap @@ -8,4 +8,12 @@ exports[`#toDataURL returns SVG image in data URL format 1`] = `"data:image/svg+ exports[`#toDataURL returns SVG image in data URL format with high DPI 1`] = `"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMzAwIDE1MCIgd2lkdGg9IjMwMCIgaGVpZ2h0PSIxNTAiPjxjaXJjbGUgcj0iMS41IiBjeD0iMTI1IiBjeT0iNTQiIGZpbGw9ImJsYWNrIj48L2NpcmNsZT48Y2lyY2xlIHI9IjEuNSIgY3g9IjE3NSIgY3k9IjU0IiBmaWxsPSJibGFjayI+PC9jaXJjbGU+PHBhdGggZD0iTSA4My4wMDAsNTcuMDAwIEMgODMuMTc0LDYwLjUxMCA4NC4wMDAsNjAuMDAwIDg1LjAwMCw2My4wMDAiIHN0cm9rZS13aWR0aD0iNS41MDgiIHN0cm9rZT0iYmxhY2siIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PC9wYXRoPjxwYXRoIGQ9Ik0gODUuMDAwLDYzLjAwMCBDIDg5LjA2MCw2OC4wNDggODguNjc0LDY4LjAxMCA5NC4wMDAsNzIuMDAwIiBzdHJva2Utd2lkdGg9IjQuNDA3IiBzdHJva2U9ImJsYWNrIiBmaWxsPSJub25lIiBzdHJva2UtbGluZWNhcD0icm91bmQiPjwvcGF0aD48cGF0aCBkPSJNIDk0LjAwMCw3Mi4wMDAgQyA5OS40ODgsNzUuNTE5IDk5LjA2MCw3Ni4wNDggMTA1LjAwMCw3OS4wMDAiIHN0cm9rZS13aWR0aD0iMy40MDIiIHN0cm9rZT0iYmxhY2siIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PC9wYXRoPjxwYXRoIGQ9Ik0gMTA1LjAwMCw3OS4wMDAgQyAxMDguNzAwLDgyLjE1NyAxMDguOTg4LDgxLjUxOSAxMTMuMDAwLDg0LjAwMCIgc3Ryb2tlLXdpZHRoPSIzLjQ5NyIgc3Ryb2tlPSJibGFjayIgZmlsbD0ibm9uZSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj48L3BhdGg+PHBhdGggZD0iTSAxMTMuMDAwLDg0LjAwMCBDIDExOS41MDAsODYuMDAwIDExOS4yMDAsODYuNjU3IDEyNi4wMDAsODguMDAwIiBzdHJva2Utd2lkdGg9IjMuMjI4IiBzdHJva2U9ImJsYWNrIiBmaWxsPSJub25lIiBzdHJva2UtbGluZWNhcD0icm91bmQiPjwvcGF0aD48cGF0aCBkPSJNIDEyNi4wMDAsODguMDAwIEMgMTMyLjQwMiw5MC40MTYgMTMyLjUwMCw5MC4wMDAgMTM5LjAwMCw5Mi4wMDAiIHN0cm9rZS13aWR0aD0iMy4yMTEiIHN0cm9rZT0iYmxhY2siIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PC9wYXRoPjxwYXRoIGQ9Ik0gMTM5LjAwMCw5Mi4wMDAgQyAxNDQuOTYxLDkzLjQ3NSAxNDQuOTAyLDkzLjQxNiAxNTEuMDAwLDk0LjAwMCIgc3Ryb2tlLXdpZHRoPSIzLjI1OCIgc3Ryb2tlPSJibGFjayIgZmlsbD0ibm9uZSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj48L3BhdGg+PHBhdGggZD0iTSAxNTEuMDAwLDk0LjAwMCBDIDE1Ni41NjksOTQuNjUyIDE1Ni40NjEsOTQuNDc1IDE2Mi4wMDAsOTQuMDAwIiBzdHJva2Utd2lkdGg9IjMuMzY2IiBzdHJva2U9ImJsYWNrIiBmaWxsPSJub25lIiBzdHJva2UtbGluZWNhcD0icm91bmQiPjwvcGF0aD48cGF0aCBkPSJNIDE2Mi4wMDAsOTQuMDAwIEMgMTY4Ljk5Miw5Mi40NjAgMTY5LjA2OSw5My4xNTIgMTc2LjAwMCw5MS4wMDAiIHN0cm9rZS13aWR0aD0iMy4wNzgiIHN0cm9rZT0iYmxhY2siIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PC9wYXRoPjxwYXRoIGQ9Ik0gMTc2LjAwMCw5MS4wMDAgQyAxODEuMDcyLDkwLjI4NSAxODAuOTkyLDg5Ljk2MCAxODYuMDAwLDg5LjAwMCIgc3Ryb2tlLXdpZHRoPSIzLjM3MiIgc3Ryb2tlPSJibGFjayIgZmlsbD0ibm9uZSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj48L3BhdGg+PHBhdGggZD0iTSAxODYuMDAwLDg5LjAwMCBDIDE5Mi41ODIsODcuMjMyIDE5Mi41NzIsODcuMjg1IDE5OS4wMDAsODUuMDAwIiBzdHJva2Utd2lkdGg9IjMuMTMzIiBzdHJva2U9ImJsYWNrIiBmaWxsPSJub25lIiBzdHJva2UtbGluZWNhcD0icm91bmQiPjwvcGF0aD48cGF0aCBkPSJNIDE5OS4wMDAsODUuMDAwIEMgMjA0LjI5Nyw4My41NjUgMjA0LjA4Miw4My4yMzIgMjA5LjAwMCw4MS4wMDAiIHN0cm9rZS13aWR0aD0iMy4yOTAiIHN0cm9rZT0iYmxhY2siIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PC9wYXRoPjxwYXRoIGQ9Ik0gMjA5LjAwMCw4MS4wMDAgQyAyMTUuMzM0LDc3LjQwNyAyMTUuMjk3LDc3LjU2NSAyMjEuMDAwLDczLjAwMCIgc3Ryb2tlLXdpZHRoPSIzLjExMyIgc3Ryb2tlPSJibGFjayIgZmlsbD0ibm9uZSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj48L3BhdGg+PHBhdGggZD0iTSAyMjEuMDAwLDczLjAwMCBDIDIyNC4xMTUsNzAuMTA3IDIyNC4zMzQsNzAuNDA3IDIyNy4wMDAsNjcuMDAwIiBzdHJva2Utd2lkdGg9IjMuNTM1IiBzdHJva2U9ImJsYWNrIiBmaWxsPSJub25lIiBzdHJva2UtbGluZWNhcD0icm91bmQiPjwvcGF0aD48L3N2Zz4="`; +exports[`#toDataURL returns SVG image with backgroundColor 1`] = `"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMzAwIDE1MCIgd2lkdGg9IjMwMCIgaGVpZ2h0PSIxNTAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9IiNmY2MiPjwvcmVjdD48Y2lyY2xlIHI9IjEuNSIgY3g9IjEyNSIgY3k9IjU0IiBmaWxsPSJibGFjayI+PC9jaXJjbGU+PGNpcmNsZSByPSIxLjUiIGN4PSIxNzUiIGN5PSI1NCIgZmlsbD0iYmxhY2siPjwvY2lyY2xlPjxwYXRoIGQ9Ik0gODMuMDAwLDU3LjAwMCBDIDgzLjE3NCw2MC41MTAgODQuMDAwLDYwLjAwMCA4NS4wMDAsNjMuMDAwIiBzdHJva2Utd2lkdGg9IjUuNTA4IiBzdHJva2U9ImJsYWNrIiBmaWxsPSJub25lIiBzdHJva2UtbGluZWNhcD0icm91bmQiPjwvcGF0aD48cGF0aCBkPSJNIDg1LjAwMCw2My4wMDAgQyA4OS4wNjAsNjguMDQ4IDg4LjY3NCw2OC4wMTAgOTQuMDAwLDcyLjAwMCIgc3Ryb2tlLXdpZHRoPSI0LjQwNyIgc3Ryb2tlPSJibGFjayIgZmlsbD0ibm9uZSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj48L3BhdGg+PHBhdGggZD0iTSA5NC4wMDAsNzIuMDAwIEMgOTkuNDg4LDc1LjUxOSA5OS4wNjAsNzYuMDQ4IDEwNS4wMDAsNzkuMDAwIiBzdHJva2Utd2lkdGg9IjMuNDAyIiBzdHJva2U9ImJsYWNrIiBmaWxsPSJub25lIiBzdHJva2UtbGluZWNhcD0icm91bmQiPjwvcGF0aD48cGF0aCBkPSJNIDEwNS4wMDAsNzkuMDAwIEMgMTA4LjcwMCw4Mi4xNTcgMTA4Ljk4OCw4MS41MTkgMTEzLjAwMCw4NC4wMDAiIHN0cm9rZS13aWR0aD0iMy40OTciIHN0cm9rZT0iYmxhY2siIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PC9wYXRoPjxwYXRoIGQ9Ik0gMTEzLjAwMCw4NC4wMDAgQyAxMTkuNTAwLDg2LjAwMCAxMTkuMjAwLDg2LjY1NyAxMjYuMDAwLDg4LjAwMCIgc3Ryb2tlLXdpZHRoPSIzLjIyOCIgc3Ryb2tlPSJibGFjayIgZmlsbD0ibm9uZSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj48L3BhdGg+PHBhdGggZD0iTSAxMjYuMDAwLDg4LjAwMCBDIDEzMi40MDIsOTAuNDE2IDEzMi41MDAsOTAuMDAwIDEzOS4wMDAsOTIuMDAwIiBzdHJva2Utd2lkdGg9IjMuMjExIiBzdHJva2U9ImJsYWNrIiBmaWxsPSJub25lIiBzdHJva2UtbGluZWNhcD0icm91bmQiPjwvcGF0aD48cGF0aCBkPSJNIDEzOS4wMDAsOTIuMDAwIEMgMTQ0Ljk2MSw5My40NzUgMTQ0LjkwMiw5My40MTYgMTUxLjAwMCw5NC4wMDAiIHN0cm9rZS13aWR0aD0iMy4yNTgiIHN0cm9rZT0iYmxhY2siIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PC9wYXRoPjxwYXRoIGQ9Ik0gMTUxLjAwMCw5NC4wMDAgQyAxNTYuNTY5LDk0LjY1MiAxNTYuNDYxLDk0LjQ3NSAxNjIuMDAwLDk0LjAwMCIgc3Ryb2tlLXdpZHRoPSIzLjM2NiIgc3Ryb2tlPSJibGFjayIgZmlsbD0ibm9uZSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj48L3BhdGg+PHBhdGggZD0iTSAxNjIuMDAwLDk0LjAwMCBDIDE2OC45OTIsOTIuNDYwIDE2OS4wNjksOTMuMTUyIDE3Ni4wMDAsOTEuMDAwIiBzdHJva2Utd2lkdGg9IjMuMDc4IiBzdHJva2U9ImJsYWNrIiBmaWxsPSJub25lIiBzdHJva2UtbGluZWNhcD0icm91bmQiPjwvcGF0aD48cGF0aCBkPSJNIDE3Ni4wMDAsOTEuMDAwIEMgMTgxLjA3Miw5MC4yODUgMTgwLjk5Miw4OS45NjAgMTg2LjAwMCw4OS4wMDAiIHN0cm9rZS13aWR0aD0iMy4zNzIiIHN0cm9rZT0iYmxhY2siIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PC9wYXRoPjxwYXRoIGQ9Ik0gMTg2LjAwMCw4OS4wMDAgQyAxOTIuNTgyLDg3LjIzMiAxOTIuNTcyLDg3LjI4NSAxOTkuMDAwLDg1LjAwMCIgc3Ryb2tlLXdpZHRoPSIzLjEzMyIgc3Ryb2tlPSJibGFjayIgZmlsbD0ibm9uZSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj48L3BhdGg+PHBhdGggZD0iTSAxOTkuMDAwLDg1LjAwMCBDIDIwNC4yOTcsODMuNTY1IDIwNC4wODIsODMuMjMyIDIwOS4wMDAsODEuMDAwIiBzdHJva2Utd2lkdGg9IjMuMjkwIiBzdHJva2U9ImJsYWNrIiBmaWxsPSJub25lIiBzdHJva2UtbGluZWNhcD0icm91bmQiPjwvcGF0aD48cGF0aCBkPSJNIDIwOS4wMDAsODEuMDAwIEMgMjE1LjMzNCw3Ny40MDcgMjE1LjI5Nyw3Ny41NjUgMjIxLjAwMCw3My4wMDAiIHN0cm9rZS13aWR0aD0iMy4xMTMiIHN0cm9rZT0iYmxhY2siIGZpbGw9Im5vbmUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PC9wYXRoPjxwYXRoIGQ9Ik0gMjIxLjAwMCw3My4wMDAgQyAyMjQuMTE1LDcwLjEwNyAyMjQuMzM0LDcwLjQwNyAyMjcuMDAwLDY3LjAwMCIgc3Ryb2tlLXdpZHRoPSIzLjUzNSIgc3Ryb2tlPSJibGFjayIgZmlsbD0ibm9uZSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIj48L3BhdGg+PC9zdmc+"`; + +exports[`#toSVG returns SVG image 1`] = `""`; + +exports[`#toSVG returns SVG image with backgroundColor 1`] = `""`; + +exports[`#toSVG returns SVG image with high DPI 1`] = `""`; + exports[`user interactions allows user to paint on the pad 1`] = `"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMzAwIDE1MCIgd2lkdGg9IjMwMCIgaGVpZ2h0PSIxNTAiPjxjaXJjbGUgcj0iMS41IiBjeD0iNTAiIGN5PSIzMCIgZmlsbD0iYmxhY2siPjwvY2lyY2xlPjxjaXJjbGUgcj0iMS41IiBjeD0iMjQwIiBjeT0iMzAiIGZpbGw9ImJsYWNrIj48L2NpcmNsZT48Y2lyY2xlIHI9IjEuNSIgY3g9IjE1MCIgY3k9IjEyMCIgZmlsbD0iYmxhY2siPjwvY2lyY2xlPjwvc3ZnPg=="`; diff --git a/tests/signature_pad.test.ts b/tests/signature_pad.test.ts index ebfd9325..f337093e 100644 --- a/tests/signature_pad.test.ts +++ b/tests/signature_pad.test.ts @@ -122,13 +122,15 @@ describe('#toData', () => { // describe('#fromDataURL', () => {}); describe('#toDataURL', () => { - // Unfortunately, results of Canvas#toDataURL depend on a platform :/ - // it('returns PNG image in data URL format', () => { - // const pad = new SignaturePad(canvas); - // pad.fromData(face); - // - // expect(pad.toDataURL('image/png')).toMatchSnapshot(); - // }); + it('returns PNG image in data URL format', () => { + const pad = new SignaturePad(canvas); + pad.fromData(face); + + // Unfortunately, results of Canvas#toDataURL depend on a platform :/ + expect(pad.toDataURL('image/png')).toEqual( + expect.stringMatching('data:image/png'), + ); + }); // Synchronous Canvas#toDataURL for JPEG images is not supported by 'canvas' library :/ // it.skip('returns JPG image in data URL format', () => {}); @@ -147,6 +149,39 @@ describe('#toDataURL', () => { expect(pad.toDataURL('image/svg+xml')).toMatchSnapshot(); }); + + it('returns SVG image with backgroundColor', () => { + const pad = new SignaturePad(canvas, { backgroundColor: '#fcc' }); + pad.fromData(face); + + expect( + pad.toDataURL('image/svg+xml', { includeBackgroundColor: true }), + ).toMatchSnapshot(); + }); +}); + +describe('#toSVG', () => { + it('returns SVG image', () => { + const pad = new SignaturePad(canvas); + pad.fromData(face); + + expect(pad.toSVG()).toMatchSnapshot(); + }); + + it('returns SVG image with high DPI', () => { + changeDevicePixelratio(2); + const pad = new SignaturePad(canvas); + pad.fromData(face); + + expect(pad.toSVG()).toMatchSnapshot(); + }); + + it('returns SVG image with backgroundColor', () => { + const pad = new SignaturePad(canvas, { backgroundColor: '#fcc' }); + pad.fromData(face); + + expect(pad.toSVG({ includeBackgroundColor: true })).toMatchSnapshot(); + }); }); describe('user interactions', () => {