Add remote signature pad (close #11)
This commit is contained in:
parent
068640c548
commit
34fd854a99
@ -100,48 +100,4 @@ html, body {
|
|||||||
.modal-dialog.modal-xxl {
|
.modal-dialog.modal-xxl {
|
||||||
max-width: 90vw;
|
max-width: 90vw;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
select option {
|
|
||||||
color: var(--bs-dark);
|
|
||||||
}
|
|
||||||
|
|
||||||
.alert {
|
|
||||||
color: var(--bs-dark);
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-purple {
|
|
||||||
background-image: linear-gradient(90deg,#33b7e2,#5e62b0,#dc307c);
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-green {
|
|
||||||
background-image: linear-gradient(90deg, #9ebd13 0%, #008552 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-red {
|
|
||||||
background-image: linear-gradient(90deg, #d53369 0%, #daae51 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-aqua {
|
|
||||||
background-image: linear-gradient(90deg, #00d2ff 0%, #3a47d5 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-ocean {
|
|
||||||
background-image: linear-gradient(90deg, #1CB5E0 0%, #000851 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-dusty {
|
|
||||||
background-image: linear-gradient(90deg, #fcff9e 0%, #c67700 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-lilac {
|
|
||||||
background-image: linear-gradient(90deg, #efd5ff 0%, #515ada 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-spring {
|
|
||||||
background-image: linear-gradient(90deg, #00C9FF 0%, #92FE9D 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-shadow {
|
|
||||||
background-image: linear-gradient(90deg, #4b6cb7 0%, #182848 100%);
|
|
||||||
}
|
}
|
54
src/css/theme.css
Normal file
54
src/css/theme.css
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2021 Netsyms Technologies.
|
||||||
|
This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
Created on : Jul 17, 2021, 12:29:13 PM
|
||||||
|
Author : Skylar Ittner
|
||||||
|
*/
|
||||||
|
|
||||||
|
select option {
|
||||||
|
color: var(--bs-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
color: var(--bs-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-purple {
|
||||||
|
background-image: linear-gradient(90deg,#33b7e2,#5e62b0,#dc307c);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-green {
|
||||||
|
background-image: linear-gradient(90deg, #9ebd13 0%, #008552 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-red {
|
||||||
|
background-image: linear-gradient(90deg, #d53369 0%, #daae51 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-aqua {
|
||||||
|
background-image: linear-gradient(90deg, #00d2ff 0%, #3a47d5 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-ocean {
|
||||||
|
background-image: linear-gradient(90deg, #1CB5E0 0%, #000851 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-dusty {
|
||||||
|
background-image: linear-gradient(90deg, #fcff9e 0%, #c67700 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-lilac {
|
||||||
|
background-image: linear-gradient(90deg, #efd5ff 0%, #515ada 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-spring {
|
||||||
|
background-image: linear-gradient(90deg, #00C9FF 0%, #92FE9D 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-shadow {
|
||||||
|
background-image: linear-gradient(90deg, #4b6cb7 0%, #182848 100%);
|
||||||
|
}
|
@ -10,6 +10,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="stylesheet" href="css/bootstrap.min.css" />
|
<link rel="stylesheet" href="css/bootstrap.min.css" />
|
||||||
<link rel="stylesheet" href="css/main.css" />
|
<link rel="stylesheet" href="css/main.css" />
|
||||||
|
<link rel="stylesheet" href="css/theme.css" />
|
||||||
<link rel="icon" href="img/icon.svg" />
|
<link rel="icon" href="img/icon.svg" />
|
||||||
|
|
||||||
<div class="modal fade" id="settingsModal" tabindex="-1" aria-labelledby="settingsModalLabel" aria-hidden="true">
|
<div class="modal fade" id="settingsModal" tabindex="-1" aria-labelledby="settingsModalLabel" aria-hidden="true">
|
||||||
@ -124,6 +125,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="btn btn-warning d-inline-block" onclick="resizeSignaturePadCanvas();signaturePad.clear();"><i class="fas fa-eraser"></i> Erase</div>
|
<div class="btn btn-warning d-inline-block" onclick="resizeSignaturePadCanvas();signaturePad.clear();"><i class="fas fa-eraser"></i> Erase</div>
|
||||||
<div class="btn btn-primary" onclick="signaturePadUndo();"><i class="fas fa-undo"></i> Undo</div>
|
<div class="btn btn-primary" onclick="signaturePadUndo();"><i class="fas fa-undo"></i> Undo</div>
|
||||||
|
<div class="btn btn-info" onclick="signatureRemoteModalOpen();"><i class="fas fa-mobile-alt"></i> Sign with Phone</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="signature-wrapper">
|
<div class="signature-wrapper">
|
||||||
@ -139,6 +141,34 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="signatureRemoteModal" tabindex="-1" aria-labelledby="signatureRemoteModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="signatureRemoteModalLabel"><i class="fas fa-mobile"></i> Remote Signature Pad Connection</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="list-group">
|
||||||
|
<div class="list-group-item">
|
||||||
|
Use a phone, tablet, or other touchscreen device as a signature pad. It must be connected to the same network (e.g. WiFi hotspot) as this computer.
|
||||||
|
On the other device, go to the website shown below, or open a camera or barcode scanner app and point it the QR code shown.
|
||||||
|
</div>
|
||||||
|
<div class="list-group-item text-center">
|
||||||
|
<span id="signatureRemoteUrlLabel"></span>
|
||||||
|
</div>
|
||||||
|
<div class="list-group-item">
|
||||||
|
<div id="signatureRemoteQRCode" class="d-flex justify-content-center p-2" style="background-color: white; border-radius: 0.5em;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="modal fade" id="verifyModal" tabindex="-1" aria-labelledby="verifyModalLabel" aria-hidden="true">
|
<div class="modal fade" id="verifyModal" tabindex="-1" aria-labelledby="verifyModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="modal-dialog modal-lg">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@ -263,6 +293,7 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||||||
<script src="node_modules/pdfjs-dist/build/pdf.min.js"></script>
|
<script src="node_modules/pdfjs-dist/build/pdf.min.js"></script>
|
||||||
<script src="node_modules/jspdf/dist/jspdf.umd.min.js"></script>
|
<script src="node_modules/jspdf/dist/jspdf.umd.min.js"></script>
|
||||||
<script src="node_modules/signature_pad/dist/signature_pad.umd.min.js"></script>
|
<script src="node_modules/signature_pad/dist/signature_pad.umd.min.js"></script>
|
||||||
|
<script src="node_modules/qrcodejs/qrcode.min.js"></script>
|
||||||
<script src="js/kbpgp-2.1.15.js"></script>
|
<script src="js/kbpgp-2.1.15.js"></script>
|
||||||
<script src="js/svg-to-image.js"></script>
|
<script src="js/svg-to-image.js"></script>
|
||||||
<script src="js/data.js"></script>
|
<script src="js/data.js"></script>
|
||||||
@ -273,4 +304,5 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|||||||
<script src="js/certbuilder.js"></script>
|
<script src="js/certbuilder.js"></script>
|
||||||
<script src="js/drawtools.js"></script>
|
<script src="js/drawtools.js"></script>
|
||||||
<script src="js/pdf.js"></script>
|
<script src="js/pdf.js"></script>
|
||||||
<script src="js/main.js"></script>
|
<script src="js/main.js"></script>
|
||||||
|
<script src="js/sigserver.js"></script>
|
@ -117,6 +117,63 @@ function activateNotarySignaturePad() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function signatureRemoteModalOpen() {
|
||||||
|
var url = getSignatureServerUrl();
|
||||||
|
$("#signatureRemoteUrlLabel").text(url);
|
||||||
|
new QRCode(document.getElementById("signatureRemoteQRCode"), url);
|
||||||
|
new bootstrap.Modal(document.getElementById('signatureRemoteModal')).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function handleRemoteSignatureData(data) {
|
||||||
|
if (!$("#signatureModal").hasClass("show")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var canvas = document.getElementById("signaturecanvas");
|
||||||
|
signaturePad.fromData(scaleSignatureData(data, canvas.width, canvas.height));
|
||||||
|
}
|
||||||
|
|
||||||
|
function scaleSignatureData(data, width, height) {
|
||||||
|
// Get width and height of data
|
||||||
|
// Get the minimum positions too for adding a bit of margin
|
||||||
|
var oldwidth = 0;
|
||||||
|
var oldheight = 0;
|
||||||
|
var oldminX = 999999999;
|
||||||
|
var oldminY = 999999999;
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
for (var j = 0; j < data[i].points.length; j++) {
|
||||||
|
oldwidth = Math.max(data[i].points[j].x, oldwidth);
|
||||||
|
oldheight = Math.max(data[i].points[j].y, oldheight);
|
||||||
|
oldminX = Math.min(data[i].points[j].x, oldminX);
|
||||||
|
oldminY = Math.min(data[i].points[j].y, oldminY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var xPad = oldminX / 2;
|
||||||
|
var yPad = oldminY / 2;
|
||||||
|
// Calculate scale ratios
|
||||||
|
var scaleX = (oldwidth + xPad * 2) / width;
|
||||||
|
var scaleY = (oldheight + yPad * 2) / height;
|
||||||
|
// Pick the largest scale ratio and use only that one so it maintains aspect ratio
|
||||||
|
var scale = Math.max(scaleX, scaleY);
|
||||||
|
// Loop over the old data and scale the points into a new signature data object
|
||||||
|
var newdata = [];
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
var newpoints = [];
|
||||||
|
for (var j = 0; j < data[i].points.length; j++) {
|
||||||
|
newpoints.push({
|
||||||
|
time: data[i].points[j].time,
|
||||||
|
x: (data[i].points[j].x + xPad) / scale,
|
||||||
|
y: (data[i].points[j].y + yPad) / scale
|
||||||
|
});
|
||||||
|
}
|
||||||
|
newdata.push({
|
||||||
|
color: data[i].color,
|
||||||
|
points: newpoints
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return newdata;
|
||||||
|
}
|
||||||
|
|
||||||
function trimAndShrinkSVG(svgstring) {
|
function trimAndShrinkSVG(svgstring) {
|
||||||
var div = document.getElementById('svgtrimbox');
|
var div = document.getElementById('svgtrimbox');
|
||||||
div.innerHTML = svgstring;
|
div.innerHTML = svgstring;
|
||||||
|
68
src/js/sigserver.js
Normal file
68
src/js/sigserver.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Netsyms Technologies.
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const http_port = 36744; // dialed ENSIG on phone keypad (eNotary Signature)
|
||||||
|
var http = require('http');
|
||||||
|
var server = http.createServer(function (req, res) {
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||||
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
|
||||||
|
if (req.method == "GET") {
|
||||||
|
console.log("Serving " + req.url);
|
||||||
|
switch (req.url) {
|
||||||
|
case "/":
|
||||||
|
res.writeHead(200, {'Content-Type': 'text/html'});
|
||||||
|
var index = getFileAsString("./sigserver/index.html");
|
||||||
|
index = index.replace("theme-BLANK", "theme-" + getStorage("color_theme"));
|
||||||
|
res.end(index);
|
||||||
|
break;
|
||||||
|
case "/bootstrap.min.css":
|
||||||
|
res.writeHead(200, {'Content-Type': 'text/css'});
|
||||||
|
res.end(getFileAsString("./css/bootstrap.min.css"));
|
||||||
|
break;
|
||||||
|
case "/theme.css":
|
||||||
|
res.writeHead(200, {'Content-Type': 'text/css'});
|
||||||
|
res.end(getFileAsString("./css/theme.css"));
|
||||||
|
break;
|
||||||
|
case "/fontawesome/all.min.js":
|
||||||
|
res.writeHead(200, {'Content-Type': 'text/javascript'});
|
||||||
|
res.end(getFileAsString("./node_modules/@fortawesome/fontawesome-free/js/all.min.js"));
|
||||||
|
break;
|
||||||
|
case "/signature_pad.umd.min.js":
|
||||||
|
res.writeHead(200, {'Content-Type': 'text/javascript'});
|
||||||
|
res.end(getFileAsString("./node_modules/signature_pad/dist/signature_pad.umd.min.js"));
|
||||||
|
break;
|
||||||
|
case "/img/signature-line.svg":
|
||||||
|
res.writeHead(200, {'Content-Type': 'image/svg+xml'});
|
||||||
|
res.end(getFileAsString("./img/signature-line.svg"));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res.writeHead(404);
|
||||||
|
res.end("404 not found.");
|
||||||
|
}
|
||||||
|
} else if (req.method == "POST") {
|
||||||
|
var body = '';
|
||||||
|
req.on('data', function (data) {
|
||||||
|
body += data;
|
||||||
|
});
|
||||||
|
req.on('end', function () {
|
||||||
|
handleRemoteSignatureData(JSON.parse(body));
|
||||||
|
});
|
||||||
|
res.writeHead(201);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
server.listen(http_port); //3 - listen for any incoming requests
|
||||||
|
console.log('Signature collection pad service running on port ' + http_port + '.');
|
||||||
|
|
||||||
|
function getSignatureServerUrl() {
|
||||||
|
const prepareUrls = require('local-ip-url/prepareUrls');
|
||||||
|
var urls = prepareUrls({
|
||||||
|
protocol: 'http',
|
||||||
|
host: '0.0.0.0',
|
||||||
|
port: http_port
|
||||||
|
});
|
||||||
|
return urls.lanUrl;
|
||||||
|
}
|
10
src/package-lock.json
generated
10
src/package-lock.json
generated
@ -488,6 +488,11 @@
|
|||||||
"verror": "1.10.0"
|
"verror": "1.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"local-ip-url": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/local-ip-url/-/local-ip-url-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-OyHVtNHgSmxr8B+6iA8sxlGrdNQJdr6M8db5/v83BdZA/cYe7+0i1XsyBQ0AoRj2nK32O3znEuPU9/b8TS6iww=="
|
||||||
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
@ -603,6 +608,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||||
},
|
},
|
||||||
|
"qrcodejs": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/qrcodejs/-/qrcodejs-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-r6tenoWFIfhZrjNtLtD5/S52zKc="
|
||||||
|
},
|
||||||
"qs": {
|
"qs": {
|
||||||
"version": "6.5.2",
|
"version": "6.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||||
|
@ -25,9 +25,11 @@
|
|||||||
"hasha": "^5.2.2",
|
"hasha": "^5.2.2",
|
||||||
"jquery": "^3.6.0",
|
"jquery": "^3.6.0",
|
||||||
"jspdf": "^2.3.1",
|
"jspdf": "^2.3.1",
|
||||||
|
"local-ip-url": "^1.0.3",
|
||||||
"nwglobal": "0.0.2",
|
"nwglobal": "0.0.2",
|
||||||
"opentimestamps": "^0.4.9",
|
"opentimestamps": "^0.4.9",
|
||||||
"pdfjs-dist": "^2.8.335",
|
"pdfjs-dist": "^2.8.335",
|
||||||
|
"qrcodejs": "^1.0.0",
|
||||||
"signature_pad": "^3.0.0-beta.4"
|
"signature_pad": "^3.0.0-beta.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
114
src/sigserver/index.html
Normal file
114
src/sigserver/index.html
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<!--
|
||||||
|
Copyright 2021 Netsyms Technologies.
|
||||||
|
This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
-->
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Signature Pad</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="stylesheet" href="bootstrap.min.css" />
|
||||||
|
<link rel="stylesheet" href="theme.css" />
|
||||||
|
<script src="fontawesome/all.min.js"></script>
|
||||||
|
<script src="signature_pad.umd.min.js"></script>
|
||||||
|
<style>
|
||||||
|
.signature-wrapper {
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: linear-gradient(125deg, rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0.2) 70%);
|
||||||
|
box-shadow: inset 1px 1px rgba(255, 255, 255, 0.2), inset -1px -1px rgba(255, 255, 255, 0.1), 1px 3px 24px -1px rgba(0, 0, 0, 0.15);
|
||||||
|
border-radius: 0 0 0.5rem 0.5rem;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
/* fix bug on iOS where image sticks out right side and makes entire page scroll horiz. */
|
||||||
|
overflow: hidden;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.signature-wrapper img {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.signature-wrapper canvas {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="theme-BLANK">
|
||||||
|
<div class="card" style="width: calc(100vw - 1rem); height: calc(100vh - 1rem); margin: 0.5rem;">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
<h6 class="card-title mb-0">Signature Pad</h6>
|
||||||
|
<div class="btn btn-warning btn-sm" onclick="resizeSignaturePadCanvas();signaturePad.clear();"><i class="fas fa-eraser"></i> Erase</div>
|
||||||
|
<div class="btn btn-primary btn-sm" onclick="signaturePadUndo();"><i class="fas fa-undo"></i> Undo</div>
|
||||||
|
<div class="btn btn-success btn-sm" onclick="sendSignature();"><i class="fas fa-check"></i> Done</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-0">
|
||||||
|
<div class="signature-wrapper">
|
||||||
|
<img src="img/signature-line.svg" />
|
||||||
|
<canvas id="signaturecanvas"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
var signaturePad = null;
|
||||||
|
|
||||||
|
function initSignaturePad() {
|
||||||
|
var canvas = document.getElementById("signaturecanvas");
|
||||||
|
signaturePad = new SignaturePad(canvas, {
|
||||||
|
backgroundColor: 'rgba(255, 255, 255, 0.5)'
|
||||||
|
});
|
||||||
|
resizeSignaturePadCanvas();
|
||||||
|
}
|
||||||
|
|
||||||
|
function resizeSignaturePadCanvas() {
|
||||||
|
var canvas = document.getElementById("signaturecanvas");
|
||||||
|
var ratio = Math.max(window.devicePixelRatio || 1, 1);
|
||||||
|
canvas.width = canvas.offsetWidth * ratio;
|
||||||
|
canvas.height = canvas.offsetHeight * ratio;
|
||||||
|
canvas.getContext("2d").scale(ratio, ratio);
|
||||||
|
if (signaturePad != null) {
|
||||||
|
signaturePad.clear(); // otherwise isEmpty() might return incorrect value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function signaturePadUndo() {
|
||||||
|
var data = signaturePad.toData();
|
||||||
|
|
||||||
|
resizeSignaturePadCanvas();
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
data.pop(); // remove the last dot or line
|
||||||
|
signaturePad.fromData(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendSignature() {
|
||||||
|
var signature = signaturePad.toData();
|
||||||
|
|
||||||
|
var xhttp = new XMLHttpRequest();
|
||||||
|
xhttp.open("POST", "/", true);
|
||||||
|
xhttp.send(JSON.stringify(signature));
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('load', function () {
|
||||||
|
initSignaturePad();
|
||||||
|
});
|
||||||
|
window.addEventListener('resize', function () {
|
||||||
|
resizeSignaturePadCanvas();
|
||||||
|
});
|
||||||
|
window.addEventListener('orientationchange', function () {
|
||||||
|
resizeSignaturePadCanvas();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
x
Reference in New Issue
Block a user