Displaying a digital signature in editable mode
Hi all,
Recently I have got a requirement in which I need to display the captured digital signature in editable mode.
SVG is is a graphic container element in HTML which stands for Scalable Vector Graphics. It used for defining graphics for the web.
Earlier we used to capture and display signatures using Canvas. But I found it is better opting for SVG rather than going for Canvas for my requirement after going through many links. I also came know that when ever we need to make a change in Canvas we need to redraw the entire scene. The main advantage of SVG is it is scalable and it supports event handlers.
Firstly I have created an OData service to get and create an entity.
The logic for get entity operation:
DATA: lt_keys TYPE /iwbep/t_mgw_tech_pairs,
ls_key TYPE /iwbep/s_mgw_tech_pair,
LV_name TYPE char20.
lt_keys = io_tech_request_context->get_keys( ). //Get key elements
**Reading key properties
READ TABLE lt_keys WITH KEY NAME = 'NAME'
INTO ls_key.
***Setting key value to a local variable
lv_name = ls_key-value.
***Retrieving data
SELECT SINGLE * from ztsvg_signature into ER_ENTITY WHERE Name = lv_name.
Create operation:
Logic is as follows:
DATA: wsvg_signature TYPE ztsvg_signature.
**Read request data
IO_DATA_PROVIDER->READ_ENTRY_DATA( IMPORTING ES_DATA = wsvg_signature ).
ER_ENTITY-Name = wsvg_signature-Name.
ER_ENTITY-SIGNURL = wsvg_signature-SIGNURL.
INSERT ztsvg_signature FROM ER_ENTITY.
In order to create an entity, perform get to read a single entity and click on use as request to perform post operation.
Create the entity as highlighted in the HTTP Request and select HTTP method as Post. Click on execute
Custom Controller:
In the custom controller, we are providing meta data to create a signature pad, its properties to capture mouse movement and the functions to get, set and clear signature details. The logic is as follows.
jQuery.sap.declare("com.finalcanvasFinal.controller.SignaturePad");
sap.ui.core.Control.extend("com.finalcanvasFinal.controller.SignaturePad", {
metadata: {
properties: {
width: {type: 'int', defaultValue: 300},
height: {type: 'int', defaultValue: 100},
bgcolor: {type: 'string', defaultValue: '#ffa'},
lineColor: {type: 'string', defaultValue: '#666'},
penColor: {type: 'string', defaultValue: '#333'},
signature: 'string'
}
},
renderer: function(oRm, oControl) {
var bgColor = oControl.getBgcolor();
var lineColor = oControl.getLineColor();
var pen = oControl.getPenColor();
var id = oControl.getId();
var w = oControl.getWidth();
var h = oControl.getHeight();
oRm.write("<div");
oRm.writeControlData(oControl);
oRm.write(">");
oRm.write('<svg xmlns="http://www.w3.org/2000/svg" width="' + w +
'" height="' + h + '" viewBox="0 0 ' + w + ' ' + h + '">');
oRm.write('<rect id="' + id + '_r" width="' + w + '" height="' + h +
'" fill="' + bgColor + '"/>');
var hh = h - 20;
oRm.write('<line x1="0" y1="' + hh + '" x2="' + w + '" y2="' + hh +
'" stroke="' + lineColor +
'" stroke-width="1" stroke-dasharray="3" ' +
'shape-rendering="crispEdges" pointer-events="none"/>');
oRm.write('<path id="' + id + '_p" stroke="' + pen + '" stroke-width="2" ' +
'fill="none" pointer-events="none"/>');
oRm.write('</svg>');
oRm.write("</div>");
},
clear: function() {
var that = this;
that.signaturePath = '';
var p = document.getElementById(that.getId() + '_p');
p.setAttribute('d', '');
},
onAfterRendering: function() {
var that = this;
that.signaturePath ='';
isDown = false;
var elm = that.$()[0];
var r = document.getElementById(that.getId() + '_r');
var p = document.getElementById(that.getId() + '_p');
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) {
that.signaturePath += 'M' + getCoords(e) + ' ';
p.setAttribute('d', that.signaturePath);
isDown = true;
if (isTouchEvent(e)) e.preventDefault();
}
function move(e) {
if (isDown) {
that.signaturePath += 'L' + getCoords(e) + ' ';
p.setAttribute('d', that.signaturePath);
}
if (isTouchEvent(e)) e.preventDefault();
}
function up(e) {
isDown = false;
if (isTouchEvent(e)) e.preventDefault();
}
r.addEventListener('mousedown', down, false);
r.addEventListener('mousemove', move, false);
r.addEventListener('mouseup', up, false);
r.addEventListener('touchstart', down, false);
r.addEventListener('touchmove', move, false);
r.addEventListener('touchend', up, false);
r.addEventListener('mouseout', up, false);
//To get signature path
if (this.getSignature()) {
this.signaturePath = this.getSignature();
var p = document.getElementById(this.getId() + '_p');
if (p) {
p.setAttribute('d', this.signaturePath);
}
}
// to set signature path to the signaturepad to display
that.setSignature = function(s) {
that.setProperty('signature', s);
that.invalidate();
};
}
});
Controller Logic:
Here I have accessed the custom controller to load all the metadata to create SVG Container and all the functions necessary to draw SVG graphics.
I have created an instance for signature pad and all other UI elements like buttons and input field for name,.
//Global variables
var prevSignature;
var isDown;
sap.ui.define([
"sap/ui/core/mvc/Controller",
"com/finalcanvasFinal/controller/SignaturePad"
], function(Controller, SignaturePad) {
"use strict";
return Controller.extend("com.finalcanvasFinal.controller.View1", {
onInit: function() {
//instance for signature pad
var oCtrl = new SignaturePad({
id: "signPad",
width: 400,
height: 200
});
//Adding signature pad to page content
var content = this.byId("signEdit");
content.addContent(oCtrl);
var that = this;
//Input field for Name
var textField = new sap.m.Input({
id: "nameValue",
width: '10rem',
placeholder: 'Name'
});
content.addContent(textField);
//Clear button to clear signaturePad
var clearButton = (new sap.m.Button({
text: 'Clear',
press: function() {
oCtrl.getSignature();
sap.ui.getCore().byId("nameValue").setValue(" ");
oCtrl.clear();
}
}));
content.addContent(clearButton);
//Accept button to save data in backend
var acceptButton = (new sap.m.Button({
text: 'Save',
press: function() {
var signaturePath = oCtrl.getSignature();
if (signaturePath !== ' ') {
var oEntry = {}; // instantiating the object
oEntry.Name = sap.ui.getCore().byId("nameValue").getValue(); //Name
oEntry.Signurl = signaturePath; //SVG path
var sServiceUrl = "/sap/opu/odata/sap/ZSVG_SIGNATURES_SRV/";
var oModel = new sap.ui.model.odata.ODataModel(sServiceUrl, false);
oModel.create("/SigntureSet()", oEntry, null, function(response) {
sap.m.MessageBox.show("Success! Data is saved");
}, function(error) {
sap.m.MessageBox.show("Error!");
});
}
}
}));
content.addContent(acceptButton);
// Adding display button
var Display = new sap.m.Button({
text: 'Display',
enabled: true,
// Displaying signature based on input
press: function() {
var Name = sap.ui.getCore().byId("nameValue").getValue(); //getting input value
var sServiceUrl = "/sap/opu/odata/sap/ZSVG_SIGNATURES_SRV/";
var oModel = new sap.ui.model.odata.ODataModel(sServiceUrl, false);
//reading details based on name
oModel.read("/SigntureSet(Name='" + Name + "')", null, null, false, function(oData, oResponse) {
prevSignature = oData.Signurl;
//Calling set signatuer method from custom controller
oCtrl.setSignature(prevSignature);
});
}
});
content.addContent(Display);
}
});
});
My view looks as follows:
When a name and signature is provided and hit save, the name and SVG path will get saved to the backend system.
In order to display the signature provide the name and click on display. The result is as follows.
Thank you..!! 🙂 🙂
That's one interesting topic! Thanks for sharing.
Is this signature captured through FIRST PHONES/ Pin Pad? (or)
What is the phone or touch device through which this signature is captured?
Kind Regards,
Prabha
Hi Prabhakaran,
I had tested it on Desktop.I will test it on phone/ tab and will let you know.
Thank you,
Sri Divya.
Great Work
<img>
in behaviorThank You Sri Divya Bandaru
Thank you Former Member
Hi divya,
I'm involved with a project where I need to use a routing concept
if i declare same pattern for two different views (view1,view2 same pattern) if i call the pattern using routing API what will happen
is it call 1st view or 2nd view or we will get error?
Thanks
Hi Jagdeesh,
It won’t raises any error even if we use same pattern for 2 views.
Based on the route you hit the corresponding target view will get loaded.
In case of single route the first view (out of two views with same pattern) whose pattern matches will get loaded.
Thank you,
SriDivya.
Hi Sri Divya,
Can we keep this Digital-Sign-Pad in a simple-form and Print it. Is it possible ?
Is there any other for this?
Thanks and Regards,
RR
Hi Raghu,
Greetings.
Yes we can keep a digital signature in a simple form and we can print it.
Please let me know if I could help you any way. 🙂
Thank you,
Sri Divya.
Hi Divya,
How are you? Thank you for your reply.
I have tried the following way, I kept the below code in form. It is not showing pdfform.
But Iam able to capture the signature on Signature-pad.
Thanks and Regards,
Raghuram
Hi Sri Divya,
I followed your process, and was able to successfully get SVG image path in my backend service. But my requirement is to use this signature in a PDF. How can I use this SVG path in a PDF form? Do we have something in ABAP to convert SVG path to XML content ?
Thanks a lot!
-Praseena
Great Work!
I've the issue, that pen, or path is not displayed...
Do you have any solution?
kr - Sven
Sri Divya where is the view created?
Hi SriDivya,
I have the similar requirement where i need to insert this SVG signature into Adobeform(SFP).
Odata value updated into Z table (Signature as String).
Is there any way to convert this Signature into JPG Image using ABAP class or FM ?
Thanks,
Liya