In one of my current projects it is one of the goals that the members of the field staff have the possibility to sign a report directly on their iPad. After some research I found the very cool jQuery plugin jSignature, which easily allows to add a signature capture field to a XPage.
The plugin is very easy to use: Just add a <div> to your XPage and initialize the plugin with the .jSignature() constructor and that’s it! The API is very simple, but provides everything needed: The captured signatures can be stored in different formats like PNG or SVG or as native Vector. Additionally they can be encoded as BASE64 or BASE30. The data can restored as easy as they can be saved: Just one API call and it’s done.
To save the signatures to a Notes document, the resulting data can be copied to a hidden input field. In the provied example above I additionally added the format of the signature. For a better handling of the generated data I decided to store the data in the SVG format, because this allows to save it directly in standard notes text field (without having problems because of the 32 K limit). This works well and the data can be displayed in standard browsers without any problems. Only in XPiNC this will not work, because the SVG format is not supported. PDFs doesn’t support SVG too, that’s why I created a converted agent using the Apache Batik framework.
I will add a demo database asap. A description of parameters to customize the plugin can be found here.
P.S. The compressed Version is not running on teamstudio Unplugged. You have to use the uncompressed Version. The example uses the x$ function of Mark Roden.
XPage example
<?xml version="1.0" encoding="UTF-8"?> <xp:view xmlns:xp="http://www.ibm.com/xsp/core"> <xp:this.resources> <xp:script src="/x$.js" clientSide="true"></xp:script> <xp:script src="/jSignatureHandler.js" clientSide="true" /> <xp:styleSheet href="/jSignature.css"></xp:styleSheet> </xp:this.resources> <xp:this.data> <xp:dominoDocument var="documentSig" formName="frmSignature" /> </xp:this.data> <script src="js/jquery-1.8.1.min.js" /> <script src="js/jSignature/jSignature.min.js" /> <xp:div id="jSignature" style="width:400.0px"></xp:div> <xp:scriptBlock id="scriptBlockSignature"> <xp:this.value><![CDATA[ $(document).ready(function() { sigHandler.init( "#{id:jSignature}", "#{id:inputHiddenSignatureData}", "#{id:inputHiddenSignatureFormat}" ); } )]]></xp:this.value> </xp:scriptBlock> <xp:button id="button1" value="Reset"> <xp:eventHandler event="onclick" submit="false"> <xp:this.script><![CDATA[ sigHandler.reset(); ]]></xp:this.script> </xp:eventHandler> </xp:button> <xp:button id="button2" value="Save"> <xp:eventHandler event="onclick" submit="true" refreshMode="complete"> <xp:this.script><![CDATA[ return sigHandler.save(); ]]></xp:this.script> <xp:this.action> <xp:saveDocument var="documentSig" /> </xp:this.action> </xp:eventHandler> </xp:button> <xp:inputHidden id="inputHiddenSignatureData" value="#{documentSignature.SignatureData}" /> <xp:inputHidden id="inputHiddenSignatureFormat" value="#{documentSignature.SignatureFormat}" /> </xp:view>
CSJS library „jSignatureHandler.js“
/**
* signatureHandler
* JS Object for handling the signature data
* Requires jSignature jQuery plugin & special
* function "x$" from Mark Roden
*
* @author Sven Hasselbach
* @category JavaScript
* @category jQuery
* @category UI
* @version 1.0
*/
var signatureHandler = function() {
_module = "signatureHandler";
_idJSignature: null; // DOM id of JSignatue DIV
_idItemData: null; // DOM id of INPUT for signature data
_idItemFormat: null; // DOM id of INPUT for signature format
_objDOMJSignature: null; // handle to DOM object
_objDOMItemData: null; // handle to DOM object
_objDOMItemFormat: null; // handle to DOM object
_maxSize = 32000; // max characters to store (32K limit!)
_format = "svg"; // format used
/**
* set DOM id of JSignature DIV
* @param String id
*/
this.setJSignatureId = function( id ){
this._idJSignature = id;
}
/**
* get DOM id of JSignature DIV
* @return String id
*/
this.getJSignatureId = function(){
return this._idJSignature;
}
/**
* set DOM id of data item
* @param String id
*/
this.setItemDataId = function( id ){
this._idItemData = id;
}
/**
* get DOM id of data item
* @return String id
*/
this.getItemDataId = function(){
return this._idItemData;
}
/**
* set DOM id of format item
* @param String id
*/
this.setItemFormatId = function( id ){
this._idItemFormat = id;
}
/**
* get DOM id of format item
* @return String id
*/
this.getItemFormatId = function(){
return this._idItemFormat;
}
/**
* get handle to DOM object of JSignature DIV
* @return Object
*/
this.getJSignatureDOMObj = function(){
return this._objDOMJSignature;
}
/**
* set handle to DOM object of JSignature DIV
* @param Object
*/
this.setJSignatureDOMObj = function( obj ){
this._objDOMSignature = obj;
}
/**
* get handle to DOM object of data item
* @return Object
*/
this.getItemDataDOMObj = function(){
return this._objDOMItemData;
}
/**
* set handle to DOM object of data item
* @param Object
*/
this.setItemDataDOMObj = function( obj ){
this._objDOMItemData = obj;
}
/**
* get handle to DOM object of format item
* @return Object
*/
this.getItemFormatDOMObj = function(){
return this._objDOMItemFormat;
}
/**
* set handle to DOM object of format item
* @param Object
*/
this.setItemFormatDOMObj = function( obj ){
this._objDOMItemFormat = obj;
}
/**
* initialize object
*
* @param String id of jSignature DIV
* @param String id of data item INPUT
* @param String id of format item INPUT
*
*/
this.init = function( idJSig, idItemData, idItemFormat ){
try{
// init jSignature
this._idJSignature = idJSig;
this._objDOMSignature = x$( this._idJSignature ) ;
this._objDOMSignature.jSignature();
// init data item
this._idItemData = idItemData;
this._objDOMItemData = x$( this._idItemData );
// init format item
this._idItemFormat = idItemFormat;
this._objDOMItemFormat = x$( this._idItemFormat );
return true;
}catch(e){
var errMsg = _module + "::" + arguments.callee.name + "\n";
for( p in e ){
errMsg += p + ": '" + e[p] + "'\n";
}
console.error( "Error!\n\n" + errMsg );
return false;
}
}
/**
* reset jSignature
*/
this.reset = function(){
try{
this._objDOMSignature.jSignature("reset");
return true;
}catch(e){
var errMsg = _module + "::" + arguments.callee.name + "\n";
for( p in e ){
errMsg += p + ": '" + e[p] + "'\n";
}
console.error( "Error!\n\n" + errMsg );
return false;
}
}
/**
* saves the data from jSignature
*
*/
this.save = function(){
try{
var datapair = this._objDOMSignature.jSignature( "getData", _format );
var format = "data:" + datapair[0];
var data = datapair[1];
// check max size!
if( data.length > _maxSize){
alert( "The size of the signature is too large. Please retry!" );
return false;
}
this._objDOMItemData.val( data );
this._objDOMItemFormat.val( format )
return true;
}catch(e){
var errMsg = _module + "::" + arguments.callee.name + "\n";
for( p in e ){
errMsg += p + ": '" + e[p] + "'\n";
}
console.error( "Error!\n\n" + errMsg );
return false;
}
}
}
// init JS instance
sigHandler = new signatureHandler();
EDIT:
Ursus created a demo database. You can find it here.
As an alternative I believe that Declan Lynch has a project on OpenNTF to do this also. Not sure what tool he used but it should be ready tongi as a custom control.
Thanks, but with jSignature you can get the signature as a bitmap in different formats, and you can restore a saved signature. The CSJS library used in the OpenNTF project stores the signatures only as coordinates and was last updated in 2010.
Hi. I was just wondering if you ever created that demo database? Thank you in advance. Ursus
Sorry Ursus, but I have never created the demo database.
I created a demo database that seems to work (without your css as I didn’t know what you did there) – would you like me to send it to you?
Sure, feel free to send it to my mail adress blog@hasselba.ch
Thanks in advance!
Hi Sven,
Do you still have the demo database created by Ursus ? Your link to the zip file is dead.
thanks
Hi Martijn, I have uploaded the missing demo file again. Regards, Sven
I have been trying to get your example working but I am running into a few problems. I’m not an experienced XPage developer so it is definitely possible I am doing something wrong.
My question are:
1. In the Xpage sample code above you bind with document „documentSig“ but then when referencing the fields in the last few lines it’s called „documentSignature“.
value=“#{documentSignature.SignatureData}“
Shouldn’t they be both called the same ?
2. In the jSignatureHandler script library you define objDOMJSignature
_objDOMJSignature: null; // handle to DOM object
But then later on you reference this._objDOMSignature without the J in it.
this._objDOMSignature = x$( this._idJSignature ) ;
this._objDOMSignature.jSignature();
Should it not always be this._objDOMJSignature with the „J“ ?
In case anybody is having problems with the Touch input no longer working (we are using Brave on mobile and touch is brocken) -> the issue is reported here:
https://github.com/willowsystems/jSignature/issues/95
there is a fix here:
https://github.com/brinley/jSignature
although there is a bug in Chromium itself that needs at least 75.0.3770.89 to work -> this is not a problem with Brave on PC but on mobile we are still at .67 for the stable version:
https://bugs.chromium.org/p/chromium/issues/detail?id=971937&q=canvas&colspec=ID%20Pri%20M%20Stars%20ReleaseBlock%20Component%20Status%20Owner%20Summary%20OS%20Modified
hope this helps somebody -> I needed the most of this week to find and fix the error -> debugging code that is a couple of years old is not fun 🙂