Created
October 4, 2019 18:57
-
-
Save mhamzas/b89bf3f2de4b12cb41c4b873110db342 to your computer and use it in GitHub Desktop.
Capture Signature using HTML5 Canvas inside Salesforce Lightning Web Component [Salesforce Files]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<lightning-card | |
title="Signature Capturing using LWC" | |
icon-name="custom:custom30"> | |
<div class="c-container"> | |
<div style="text-align: center; "> | |
<h2 class="slds-text-heading_medium slds-m-bottom_medium"> | |
Sign Here | |
</h2> | |
<p class="slds-m-bottom_small"> | |
<canvas name="canvasItem" style="border:2px solid rgb(136, 135, 135); | |
background: transparent;"></canvas> | |
</p> | |
<p class="slds-m-bottom_small"> | |
<lightning-button variant="brand" label="Save" title="Save" | |
onclick={handleSaveClick} class="slds-m-left_x-small"></lightning-button> | |
<lightning-button variant="brand" label="Clear" title="Clear" | |
onclick={handleClearClick} class="slds-m-left_x-small"></lightning-button> | |
</p> | |
</div> | |
</div> | |
</lightning-card> | |
</template> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable no-unused-vars */ | |
/* eslint-disable no-console */ | |
import { LightningElement,api } from 'lwc'; | |
import saveSign from '@salesforce/apex/SignatureHelper.saveSign'; | |
import { ShowToastEvent } from 'lightning/platformShowToastEvent'; | |
//declaration of variables for calculations | |
let isDownFlag, | |
isDotFlag = false, | |
prevX = 0, | |
currX = 0, | |
prevY = 0, | |
currY = 0; | |
let x = "#0000A0"; //blue color | |
let y = 1.5; //weight of line width and dot. | |
let canvasElement, ctx; //storing canvas context | |
let attachment; //holds attachment information after saving the sigture on canvas | |
let dataURL,convertedDataURI; //holds image data | |
export default class CapturequestedEventignature extends LightningElement { | |
@api recordId; | |
//event listeners added for drawing the signature within shadow boundary | |
constructor() { | |
super(); | |
this.template.addEventListener('mousemove', this.handleMouseMove.bind(this)); | |
this.template.addEventListener('mousedown', this.handleMouseDown.bind(this)); | |
this.template.addEventListener('mouseup', this.handleMouseUp.bind(this)); | |
this.template.addEventListener('mouseout', this.handleMouseOut.bind(this)); | |
} | |
//retrieve canvase and context | |
renderedCallback(){ | |
canvasElement = this.template.querySelector('canvas'); | |
ctx = canvasElement.getContext("2d"); | |
} | |
//handler for mouse move operation | |
handleMouseMove(event){ | |
this.searchCoordinatesForEvent('move', event); | |
} | |
//handler for mouse down operation | |
handleMouseDown(event){ | |
this.searchCoordinatesForEvent('down', event); | |
} | |
//handler for mouse up operation | |
handleMouseUp(event){ | |
this.searchCoordinatesForEvent('up', event); | |
} | |
//handler for mouse out operation | |
handleMouseOut(event){ | |
this.searchCoordinatesForEvent('out', event); | |
} | |
/* | |
handler to perform save operation. | |
save signature as attachment. | |
after saving shows success or failure message as toast | |
*/ | |
handleSaveClick(){ | |
//set to draw behind current content | |
ctx.globalCompositeOperation = "destination-over"; | |
ctx.fillStyle = "#FFF"; //white | |
ctx.fillRect(0,0,canvasElement.width, canvasElement.height); | |
//convert to png image as dataURL | |
dataURL = canvasElement.toDataURL("image/png"); | |
//convert that as base64 encoding | |
convertedDataURI = dataURL.replace(/^data:image\/(png|jpg);base64,/, ""); | |
//call Apex method imperatively and use promise for handling sucess & failure | |
saveSign({strSignElement: convertedDataURI,recId : this.recordId}) | |
.then(result => { | |
//this.ContentDocumentLink = result; | |
//console.log('ContentDocumentId=' + this.ContentDocumentLink.ContentDocumentId); | |
//show success message | |
this.dispatchEvent( | |
new ShowToastEvent({ | |
title: 'Success', | |
message: 'Salesforce File created with Signature', | |
variant: 'success', | |
}), | |
); | |
}) | |
.catch(error => { | |
//show error message | |
this.dispatchEvent( | |
new ShowToastEvent({ | |
title: 'Error creating Salesforce File record', | |
message: error.body.message, | |
variant: 'error', | |
}), | |
); | |
}); | |
} | |
//clear the signature from canvas | |
handleClearClick(){ | |
ctx.clearRect(0, 0, canvasElement.width, canvasElement.height); | |
} | |
searchCoordinatesForEvent(requestedEvent, event){ | |
event.preventDefault(); | |
if (requestedEvent === 'down') { | |
this.setupCoordinate(event); | |
isDownFlag = true; | |
isDotFlag = true; | |
if (isDotFlag) { | |
this.drawDot(); | |
isDotFlag = false; | |
} | |
} | |
if (requestedEvent === 'up' || requestedEvent === "out") { | |
isDownFlag = false; | |
} | |
if (requestedEvent === 'move') { | |
if (isDownFlag) { | |
this.setupCoordinate(event); | |
this.redraw(); | |
} | |
} | |
} | |
//This method is primary called from mouse down & move to setup cordinates. | |
setupCoordinate(eventParam){ | |
//get size of an element and its position relative to the viewport | |
//using getBoundingClientRect which returns left, top, right, bottom, x, y, width, height. | |
const clientRect = canvasElement.getBoundingClientRect(); | |
prevX = currX; | |
prevY = currY; | |
currX = eventParam.clientX - clientRect.left; | |
currY = eventParam.clientY - clientRect.top; | |
} | |
//For every mouse move based on the coordinates line to redrawn | |
redraw() { | |
ctx.beginPath(); | |
ctx.moveTo(prevX, prevY); | |
ctx.lineTo(currX, currY); | |
ctx.strokeStyle = x; //sets the color, gradient and pattern of stroke | |
ctx.lineWidth = y; | |
ctx.closePath(); //create a path from current point to starting point | |
ctx.stroke(); //draws the path | |
} | |
//this draws the dot | |
drawDot(){ | |
ctx.beginPath(); | |
ctx.fillStyle = x; //blue color | |
ctx.fillRect(currX, currY, y, y); //fill rectrangle with coordinates | |
ctx.closePath(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="captureSignature"> | |
<apiVersion>46.0</apiVersion> | |
<isExposed>true</isExposed> | |
<targets> | |
<target>lightning__RecordPage</target> | |
<target>lightning__AppPage</target> | |
<target>lightning__HomePage</target> | |
</targets> | |
</LightningComponentBundle> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public with sharing class SignatureHelper { | |
@AuraEnabled | |
public static void saveSign(String strSignElement,Id recId){ | |
// Create Salesforce File | |
//Insert ContentVersion | |
ContentVersion cVersion = new ContentVersion(); | |
cVersion.ContentLocation = 'S'; //S-Document is in Salesforce. E-Document is outside of Salesforce. L-Document is on a Social Netork. | |
cVersion.PathOnClient = 'Signature-'+System.now() +'.png';//File name with extention | |
cVersion.Origin = 'H';//C-Content Origin. H-Chatter Origin. | |
//cVersion.OwnerId = attach.OwnerId;//Owner of the file | |
cVersion.Title = 'Signature-'+System.now() +'.png';//Name of the file | |
cVersion.VersionData = EncodingUtil.base64Decode(strSignElement);//File content | |
Insert cVersion; | |
//After saved the Content Verison, get the ContentDocumentId | |
Id conDocument = [SELECT ContentDocumentId FROM ContentVersion WHERE Id =:cVersion.Id].ContentDocumentId; | |
//Insert ContentDocumentLink | |
ContentDocumentLink cDocLink = new ContentDocumentLink(); | |
cDocLink.ContentDocumentId = conDocument;//Add ContentDocumentId | |
cDocLink.LinkedEntityId = recId;//Add attachment parentId | |
cDocLink.ShareType = 'I';//V - Viewer permission. C - Collaborator permission. I - Inferred permission. | |
cDocLink.Visibility = 'AllUsers';//AllUsers, InternalUsers, SharedUsers | |
Insert cDocLink; | |
// Create attachement | |
/* | |
Attachment objAttachment = new Attachment(); | |
objAttachment.Name = 'Demo-Signature.png'; | |
objAttachment.ParentId = recId; | |
objAttachment.ContentType = 'image/png'; | |
objAttachment.Body = EncodingUtil.base64Decode(strSignElement); | |
insert objAttachment; | |
return objAttachment; | |
*/ | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment