Saturday 17 February 2018

Signature Pad And Save Signature In to Object Using Lightning Components

Signature Pad using lightning components:

In this topic , we will display digital signature pad using lightning components and it will be responsive also. we will save the signature in to object also.

Note: This signature pad is not using any third party file . We will use our custom js in our lighting component.




Follow the steps below--

Step 1:  Create lightning component "ESignature.cmp" and use below code in this component.

<aura:component controller="SignatureCtr"  implements="force:appHostable">
    <ltng:require afterScriptsLoaded="{!c.Init}"/>
    <div style="text-align: center;">
        <canvas aura:id="can" style="border:2px solid #ddd;background: transparent;"></canvas>
    </div>
    <div style="text-align: center;margin: 7px;">
        <button class="slds-button slds-button_brand" onclick="{!c.erase}">Clear</button>
        <button class="slds-button slds-button_brand" onclick="{!c.save}">Save</button>
    </div>
</aura:component>

Step 2: Now create "ESignatureController.js" by click on controller and use below code in this controller.

({
    Init : function(component, event, helper) {
        helper.doInit(component, event, helper);
    },
    erase:function(component, event, helper){
        helper.eraseHelper(component, event, helper);
    },
    save:function(component, event, helper){
        helper.saveHelper(component, event, helper);
    }
})
Step 3: Now create "ESignatureHelper.js" by click on helper and use below code in this helper.

({
    doInit : function(component, event, helper) {
            var canvas, ctx, flag = false,
            prevX = 0,
            currX = 0,
            prevY = 0,
            currY = 0,
            dot_flag = false;
       
        var x = "black",
            y = 2,
            w,h;
        canvas=component.find('can').getElement();
        var ratio = Math.max(window.devicePixelRatio || 1, 1);
        w = canvas.width*ratio;
        h = canvas.height*ratio;
        ctx = canvas.getContext("2d");
        console.log('ctx:='+ctx);
       
        canvas.addEventListener("mousemove", function (e) {
            findxy('move', e)
        }, false);
        canvas.addEventListener("mousedown", function (e) {
            findxy('down', e)
        }, false);
        canvas.addEventListener("mouseup", function (e) {
            findxy('up', e)
        }, false);
        canvas.addEventListener("mouseout", function (e) {
            findxy('out', e)
        }, false);
        // Set up touch events for mobile, etc
        canvas.addEventListener("touchstart", function (e) {
            var touch = e.touches[0];
            console.log('touch start:='+touch);
            var mouseEvent = new MouseEvent("mousedown", {
                clientX: touch.clientX,
                clientY: touch.clientY
            });
            canvas.dispatchEvent(mouseEvent);
             e.preventDefault();
        }, false);
        canvas.addEventListener("touchend", function (e) {
            var mouseEvent = new MouseEvent("mouseup", {});
            canvas.dispatchEvent(mouseEvent);
        }, false);
        canvas.addEventListener("touchmove", function (e) {
            var touch = e.touches[0];
            var mouseEvent = new MouseEvent("mousemove", {
                clientX: touch.clientX,
                clientY: touch.clientY
            });
            canvas.dispatchEvent(mouseEvent);
             e.preventDefault();
           
        }, false);
       
        // Get the position of a touch relative to the canvas
        function getTouchPos(canvasDom, touchEvent) {
            var rect = canvasDom.getBoundingClientRect();
            return {
                x: touchEvent.touches[0].clientX - rect.left,
                y: touchEvent.touches[0].clientY - rect.top
            };
        }
       
        function findxy(res, e){
            const rect = canvas.getBoundingClientRect();
            if (res == 'down') {
                prevX = currX;
                prevY = currY;
                currX = e.clientX - rect.left ;
                currY = e.clientY -  rect.top;
               
                flag = true;
                dot_flag = true;
                if (dot_flag) {
                    ctx.beginPath();
                    ctx.fillStyle = x;
                    ctx.fillRect(currX, currY, 2, 2);
                    ctx.closePath();
                    dot_flag = false;
                }
            }
            if (res == 'up' || res == "out") {
                flag = false;
            }
            if (res == 'move') {
                if (flag) {
                    prevX = currX;
                    prevY = currY;
                    currX = e.clientX -  rect.left;
                    currY = e.clientY - rect.top;
                    draw(component,ctx);
                }
            }
        }
        function draw() {
            ctx.beginPath();
            ctx.moveTo(prevX, prevY);
            ctx.lineTo(currX, currY);
            ctx.strokeStyle = x;
            ctx.lineWidth = y;
            ctx.stroke();
            ctx.closePath();
        }
       
    },
    eraseHelper: function(component, event, helper){
        var m = confirm("Want to clear");
        if (m) {
            var canvas=component.find('can').getElement();
            var ctx = canvas.getContext("2d");
            var w = canvas.width;
            var h = canvas.height;
            ctx.clearRect(0, 0, w, h);
       }
    },
    saveHelper:function(component, event, helper){
        var pad=component.find('can').getElement();
        var dataUrl = pad.toDataURL();
        console.log('dataUrl:='+dataUrl);
        var strDataURI=dataUrl.replace(/^data:image\/(png|jpg);base64,/, "");
        var action = component.get("c.saveSignature");
        action.setParams({
            signatureBody : strDataURI
        });
        action.setCallback(this,function(res){
            var state = res.getState();
            if(state==="SUCCESS"){
                alert("Signature saved successfully");
            }
        });       
        $A.enqueueAction(action);
    }
})


Step 4: So We have created working signature pad . Now we will save that signature in our object.
So here I create a object  and provide a custom record id in attachment. but you can use any object to save attachment .

Now create a apex class name "SignatureCtr" use below code in class:

public class SignatureCtr{
    @AuraEnabled
    public static void saveSignature(String signatureBody){
       Attachment a = new Attachment();
        a.ParentId = 'a097F00000765JA'; // record id of object.
        a.Body = EncodingUtil.base64Decode(signatureBody);
        a.ContentType = 'image/png';
        a.Name = 'Signature Capture.png';
        insert a;
    }
}
  

So signature pad created successfully ans saved in to object successfully also.


2 comments:

  1. Is it possible to resize the canvas? So that height is bigger so users can sign landscape on mobile. I've tried changing the code, but nothing seems to affect the size. Not sure if this is a salesforce limitation or if I'm just doing it wrong.

    ReplyDelete
  2. Am i only the one who can see the code in a single vertical line, please chagne it ,it will be useful

    ReplyDelete

If you have any doubts, please let me know.