Capture Signature using HTML5 and iPad
IpadHtmlCanvasSvgIpad Problem Overview
Anyone know how this can be done? Would you use a canvas object, svg, jQuery, etc?
Ipad Solutions
Solution 1 - Ipad
Here's another canvas based version with variable width (based on drawing velocity) curves: demo at http://szimek.github.io/signature_pad and code at https://github.com/szimek/signature_pad.
Solution 2 - Ipad
A canvas element with some JavaScript would work great.
In fact, Signature Pad (a jQuery plugin) already has this implemented.
Solution 3 - Ipad
Here is http://mcc.id.au/2010/signature.html">a quickly hacked up version of this using SVG I just did. Works well for me on my iPhone. Also works in a desktop browser using normal mouse events.
Solution 4 - Ipad
Perhaps the best two browser techs for this are Canvas, with Flash as a back up.
We tried VML on IE as backup for Canvas, but it was much slower than Flash. SVG was slower then all the rest.
With jSignature ( http://willowsystems.github.com/jSignature/ ) we used Canvas as primary, with fallback to Flash-based Canvas emulator (FlashCanvas) for IE8 and less. Id' say worked very well for us.
Solution 5 - Ipad
The options already listed are very good, however here a few more on this topic that I've researched and came across.
1) http://perfectionkills.com/exploring-canvas-drawing-techniques/<br/>
2) http://mcc.id.au/2010/signature.html<br/>
3) https://zipso.net/a-simple-touchscreen-sketchpad-using-javascript-and-html5/<br/>
And as always you may want to save the canvas to image:
http://www.html5canvastutorials.com/advanced/html5-canvas-save-drawing-as-an-image/
good luck and happy signing
Solution 6 - Ipad
@szimek (selected answer) has a well-documented solution for those who want a full-featured module with a MIT license that's good-to-go. @heycam has a simpler solution that requires no libraries or plugins, has no licenses, and can be easily customized; all of which makes it a better fit for my needs. This post tries to explain how exactly his solution works.
Basic workflow:
- Create a functionally blank
svg
to contain the signature - Reserve a
path
element inside the containersvg
- Use touch events (
touchstart
,touchmove
,touchend
) for the user to draw the signature using touch inputs - Use mouse events (
mousedown
,mousemove
,mouseup
,mouseout
) for the user to draw the signature using mouse inputs - On each event, detect the type of input (touch, mouse) to get the X,Y coordinates of the path the user is drawing
- Append each path to the
d
attribute (path coordinates) of thepath
element so it displays to the user - Add a helper function to output the signature path (
path.d
), which is just astring
you can plug back into thepath.d
later on to restore the signature - Add a helper function to clear the
path.d
value
Here's @heycam's solution as a runnable snippet:
//init
let r = document.getElementById('r'),
p = document.getElementById('p'),
signaturePath = '',
isDown = false,
svg = document.getElementById('sig_panel'),
b_show = document.getElementById('show'),
b_clear = document.getElementById('clear'),
pathdata = document.getElementById('pathdata');
//drawing functions
function isTouchEvent(e) {
return e.type.match(/^touch/);
}
function getCoords(e) {
if (isTouchEvent(e)) {
return e.targetTouches[0].clientX + ',' + e.targetTouches[0].clientY;
}
return e.clientX + ',' + e.clientY;
}
function down(e) {
signaturePath += 'M' + getCoords(e) + ' ';
p.setAttribute('d', signaturePath);
isDown = true;
if (isTouchEvent(e)) e.preventDefault();
}
function move(e) {
if (isDown) {
signaturePath += 'L' + getCoords(e) + ' ';
p.setAttribute('d', signaturePath);
}
if (isTouchEvent(e)) e.preventDefault();
}
function up(e) {
isDown = false;
if (isTouchEvent(e)) e.preventDefault();
}
//input handlers
r.addEventListener('touchstart', down, false);
r.addEventListener('touchmove', move, false);
r.addEventListener('touchend', up, false);
r.addEventListener('mousedown', down, false);
r.addEventListener('mousemove', move, false);
r.addEventListener('mouseup', up, false);
r.addEventListener('mouseout', up, false);
//helper functions
function clearSignature() {
pathdata.textContent = '';
signaturePath = '';
p.setAttribute('d', '');
}
function getSignature() {
pathdata.textContent = signaturePath;
return signaturePath;
}
//button handlers
b_show.addEventListener('click', getSignature);
b_clear.addEventListener('click', clearSignature);
svg {
margin: .5em;
border: 1px solid gray;
border-radius: .5em;
}
.flex {
display: flex;
}
button {
margin: .5em;
}
#pathdata {
font-family: monospace;
background: #ddd;
padding: 1em;
margin: 1em .5em;
}
<svg id="sig_panel" xmlns="http://www.w3.org/2000/svg" width="300" height="100" viewBox="0 0 300 100">
<rect id="r" width="300" height="100" fill="#ffa"/>
<line x1="0" y1="80" x2="300" y2="80" stroke="#666" stroke-width="1" stroke-dasharray="3" shape-rendering="crispEdges" pointer-events="none"/>
<path id="p" stroke="navy" stroke-width="2" fill="none" pointer-events="none"/>
</svg>
<div class="flex">
<button id="show">Show signaure path data</button>
<button id="clear">Clear signature</button>
</div>
<div id="pathdata"></div>
Saving the path.d
value on the server (and client cache) is all I need. Others may need to save the entire svg
itself with path.d
filled in, or convert it to other formats (JPEG, PNG, PDF) using appropriate converters (not covered here).
I plan to go a step beyond and add user controls to manage the following:
- line thickness:
path.stroke-width
- line color:
path.stroke
- line quality:
path.shape-rendering
and theme the signature field (as part of my custom form lib):
- container dimensions:
rect.width
,rect.height
- container background:
rect.fill
- eliminate the "sign here" line:
line
Solution 7 - Ipad
Another OpenSource signature field is https://github.com/applicius/jquery.signfield/ , registered jQuery plugin using Sketch.js .