Neste exemplo, vou mostrar como implementar um campo para assinatura digital usando o elemento Canvas do HTML5.
Acesse o demo para testar no navegador.
Recomendo o uso de uma caneta touch screen como essa para uso em Tablet e Smartphones:
Estrutura do Formulário
Variáveis
- assinaturaBase64: Variável do tipo Text, que vai receber a Imagem da assinatura no formato Base64 do lado do servidor.
Campos
- elmCanvas: Campo do tipo HtmlElement que vai conter o elemento Canvas. Informe o código abaixo na propriedade Template Html:
<canvas id="board"></canvas>
- btnConfirmar: Campo do tipo Button. Ao clicar neste botão, a imagem será enviada para o servidor no formato Base64.
Procedimentos
-
btnConfirmar_Click: Este procedimento será chamado no evento Click do botão btnConfirmar. Neste procedimento, será possível acessar a variável assinaturaBase64 e grava-la no banco de dados. Neste exemplo, vamos apenas mostrar uma mensagem informando que o arquivo foi recebido:
Arquivos JavaScript
Adicione estes dois arquivos Javascript no Formulário. O nome dos arquivos não precisa ser os mesmos:
- signature-manager.js: Script que gerencia a area de desenho da assinatura. E neste arquivo que os eventos de mouse e a configuração do canvas são gerenciados.
var latromi = latromi || {}; latromi.esignature = function (canvas, settings) { let ctx; let drawing = false; function getPos(canvasDom, mouseEvent) { var clientRect = canvasDom.getBoundingClientRect(); return { x: mouseEvent.clientX - clientRect.x, y: mouseEvent.clientY - clientRect.y } } function getTouchPos(canvasDom, touchEvent) { var rect = canvasDom.getBoundingClientRect(); return { x: touchEvent.touches[0].clientX - rect.left, y: touchEvent.touches[0].clientY - rect.top }; } function onCanvasMouseDown(evt) { var pos = getPos(canvas, evt); ctx.moveTo(pos.x, pos.y); drawing = true; } function onCanvasMouseUp(evt) { drawing = false; } function onCanvasMouseMove(evt) { if (drawing) { var pos = getPos(canvas, evt); ctx.lineTo(pos.x, pos.y); ctx.stroke(); } } function applySettings() { if (settings.width) canvas.width = settings.width; if (settings.height) canvas.height = settings.height; if (settings.lineWidth) ctx.lineWidth = 4; ctx.imageSmoothingEnabled=true; // Aplica cor de fundo no canvas if (typeof settings.backcolor === "string") { ctx.fillStyle = settings.backcolor; ctx.fillRect(0, 0, canvas.width, canvas.height); } } // ########### [Configuração do Canvas - Inicio] ########### ctx = canvas.getContext("2d"); canvas.addEventListener('mousedown', onCanvasMouseDown); canvas.addEventListener('mouseup' , onCanvasMouseUp); canvas.addEventListener('mousemove', onCanvasMouseMove); // Converte eventos TouchScreen em enventos de Mouse canvas.addEventListener('touchstart', function (evt) { var touch = evt.touches[0]; var mouseEvent = new MouseEvent("mousedown", { clientX: touch.clientX, clientY: touch.clientY }); canvas.dispatchEvent(mouseEvent); }, false); // canvas.addEventListener('touchend', function (evt) { var mouseEvent = new MouseEvent("mouseup", { }); canvas.dispatchEvent(mouseEvent); }, false); // canvas.addEventListener('touchmove', function (evt) { var touch = evt.touches[0]; var mouseEvent = new MouseEvent("mousemove", { clientX: touch.clientX, clientY: touch.clientY }); canvas.dispatchEvent(mouseEvent); }, false); // Adiciona link para limpar e tentar novamente. var clearLink = document.createElement('a'); clearLink.href='#'; clearLink.innerHTML = 'Tentar novamente'; clearLink.title = 'Clique aqui para limpar a assinatura e tentar novamente'; clearLink.addEventListener('click', function(evt) { evt.preventDefault(); canvas.width = canvas.width; applySettings(); }); canvas.parentNode.insertBefore(clearLink, canvas); // // Evita rolagem quando o usuário tocar no canvas document.body.addEventListener("touchstart", function (e) { if (e.target == canvas) e.preventDefault(); }, false); document.body.addEventListener("touchend", function (e) { if (e.target == canvas) e.preventDefault(); }, false); document.body.addEventListener("touchmove", function (e) { if (e.target == canvas) e.preventDefault(); }, false); applySettings(); // ########### [Configuração do Canvas - Fim] ########### return { } };
- form-assinatura-digital.js: Este Script manda a imagem do Canvas que está no navegador para o servidor, quando o usuário clica no botão btnConfirmar:
var latromi = latromi || {}; latromi.myForm = function () { function onFormCreatedPrivate(arguments) { let board = document.getElementById('board'); new latromi.esignature(board, { width: $(board.parentElement).width(), height: $(board.parentElement).height(), lineWidth: 4, backcolor: "white" }); } function onEventFiringPrivate(arguments){ console.log('Evento ' + arguments.eventName + ' disparado.'); if (arguments.eventKind === 'Field' && arguments.field.name === 'btnConfirmar' && arguments.eventName === 'Click') { let board = document.getElementById('board'); let base64 = board.toDataURL("image/png").replace("image/png", "image/octet-stream") arguments.form.setVariableValue('assinaturaBase64', base64); } } function onFieldValueChangedPrivate(arguments){ console.log('O valor do campo ' + arguments.field.name + ' foi alterado.'); } return { onFormCreated: function(arguments) { onFormCreatedPrivate(arguments); }, onEventFiring: function(arguments) { onEventFiringPrivate(arguments); }, onFieldValueChanged: function(arguments) { onFieldValueChangedPrivate(arguments); } } }; // Declara o formulário var myForm = new latromi.myForm(); // Adiciona Callbacks no Formulário latromi.formManager.setOnFormCreatedCallback( myForm.onFormCreated ); latromi.formManager.setOnEventFiringCallback( myForm.onEventFiring ); latromi.formManager.setOnFieldValueChangedCallback( myForm.onFieldValueChanged );