En este post te mostraré cómo solicitar la firma a un usuario desde la web usando JavaScript, de modo que el usuario pueda firmar como si lo hiciera en una hoja de papel.
Después podremos enviar esa firma al servidor, descargarla, colocarla en un documento, etcétera.
Quiero que quede claro que vamos a solicitar la firma manuscrita usando programación en la web a través de un navegador. Para ello vamos a usar el canvas.
Nota: una vez que la firma haya sido dibujada puedes enviarla a PHP, Java, Node, etcétera. En el ejemplo te mostraré cómo descargarla como imagen y colocarla en un documento.
Preparando el canvas
No voy a profundizar en cómo hacer que el usuario dibuje en el canvas, pues eso ya lo expliqué en mi post de un prototipo de Paint en JavaScript. Así que te invito a leerlo para que no tengas dudas de lo que haremos.
A continuación te muestro el canvas con los botones que van a permitir limpiarlo, descargar la firma como imagen o generar un documento con la firma.
Por cierto, recuerda que ya he explicado cómo limpiar el canvas y cómo descargar el canvas como imagen. Aquí solo me enfocaré en recoger la firma del usuario con JavaScript.
<!--
____ _____ _ _ _
| _ \ | __ \ (_) | | |
| |_) |_ _ | |__) |_ _ _ __ _____| |__ _ _| |_ ___
| _ <| | | | | ___/ _` | '__|_ / | '_ \| | | | __/ _ \
| |_) | |_| | | | | (_| | | / /| | |_) | |_| | || __/
|____/ \__, | |_| \__,_|_| /___|_|_.__/ \__, |\__\___|
__/ | __/ |
|___/ |___/
____________________________________
/ Si necesitas ayuda, contáctame en \
\ https://parzibyte.me /
------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Creado por Parzibyte (https://parzibyte.me).
------------------------------------------------------------------------------------------------
| IMPORTANTE |
Si vas a borrar este encabezado, considera:
Seguirme: https://parzibyte.me/blog/sigueme/
Y compartir mi blog con tus amigos
También tengo canal de YouTube: https://www.youtube.com/channel/UCroP4BTWjfM0CkGB6AFUoBg?sub_confirmation=1
Twitter: https://twitter.com/parzibyte
Facebook: https://facebook.com/parzibyte.fanpage
Instagram: https://instagram.com/parzibyte
Hacer una donación vía PayPal: https://paypal.me/LuisCabreraBenito
------------------------------------------------------------------------------------------------
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Solicitar firma de usuario - By Parzibyte</title>
<link rel="stylesheet" href="estilo.css">
</head>
<body>
<p>Firmar a continuación:</p>
<canvas id="canvas"></canvas>
<br>
<button id="btnLimpiar">Limpiar</button>
<button id="btnDescargar">Descargar</button>
<button id="btnGenerarDocumento">Pasar a documento</button>
<br>
<a href="https://parzibyte.me/blog">By Parzibyte</a>
<script src="script.js"></script>
</body>
</html>
Dibujar en canvas
Te dejo el código encargado de permitir que se dibuje con el mouse, aunque ya lo expliqué a profundidad en otro artículo.
// Lo demás tiene que ver con pintar sobre el canvas en los eventos del mouse
$canvas.addEventListener("mousedown", evento => {
// En este evento solo se ha iniciado el clic, así que dibujamos un punto
xAnterior = xActual;
yAnterior = yActual;
xActual = obtenerXReal(evento.clientX);
yActual = obtenerYReal(evento.clientY);
contexto.beginPath();
contexto.fillStyle = COLOR_PINCEL;
contexto.fillRect(xActual, yActual, GROSOR, GROSOR);
contexto.closePath();
// Y establecemos la bandera
haComenzadoDibujo = true;
});
$canvas.addEventListener("mousemove", (evento) => {
if (!haComenzadoDibujo) {
return;
}
// El mouse se está moviendo y el usuario está presionando el botón, así que dibujamos todo
xAnterior = xActual;
yAnterior = yActual;
xActual = obtenerXReal(evento.clientX);
yActual = obtenerYReal(evento.clientY);
contexto.beginPath();
contexto.moveTo(xAnterior, yAnterior);
contexto.lineTo(xActual, yActual);
contexto.strokeStyle = COLOR_PINCEL;
contexto.lineWidth = GROSOR;
contexto.stroke();
contexto.closePath();
});
["mouseup", "mouseout"].forEach(nombreDeEvento => {
$canvas.addEventListener(nombreDeEvento, () => {
haComenzadoDibujo = false;
});
});
Limpiar canvas
Al inicio de todo colocamos el color de fondo en blanco para que el canvas se vea limpio. También escuchamos el clic del botón que limpia el lienzo e invocamos a esa función.
const limpiarCanvas = () => {
// Colocar color blanco en fondo de canvas
contexto.fillStyle = COLOR_FONDO;
contexto.fillRect(0, 0, $canvas.width, $canvas.height);
};
limpiarCanvas();
$btnLimpiar.onclick = limpiarCanvas;
Descargar firma como imagen
Veamos el primer caso en el que el usuario quiere descargar su firma como una imagen. El código se ve así:
// Escuchar clic del botón para descargar el canvas
$btnDescargar.onclick = () => {
const enlace = document.createElement('a');
// El título
enlace.download = "Firma.png";
// Convertir la imagen a Base64 y ponerlo en el enlace
enlace.href = $canvas.toDataURL();
// Hacer click en él
enlace.click();
};
Y con esto el usuario podrá descargar la firma manuscrita. Te repito que lo de convertir el canvas a imagen ya lo expliqué en otro post, regresa a los párrafos anteriores a buscarlo si tienes dudas.
Generar documento con firma de usuario
Ahora veamos otra cosa interesante. Una vez que el usuario ha firmado usando el mouse podemos pasar esa firma a un documento HTML e incrustar esa imagen. Primero veamos la plantilla del documento en cuestión:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documento con firma - By Parzibyte</title>
<style>
img {
display: block;
margin-left: auto;
margin-right: auto;
}
</style>
</head>
<body>
<h1>Título del documento</h1>
<strong>Simple documento para demostrar cómo se puede colocar una firma del usuario</strong>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Et magnam eius reprehenderit repudiandae, veritatis
aliquid a iste! Eos necessitatibus omnis maiores doloremque? Ipsam rem omnis saepe architecto quam molestias
asperiores.</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Quam unde veritatis, aut exercitationem in voluptatum
aliquid rem deleniti non quas dignissimos asperiores laborum omnis similique esse, neque autem sit possimus.</p>
<p>Quos veniam incidunt animi distinctio, itaque voluptate laudantium voluptates doloribus ipsa praesentium qui
veritatis perferendis rerum dicta a, non esse cupiditate nemo mollitia exercitationem nesciunt explicabo,
debitis dolores. Mollitia, similique.</p>
<p>Deleniti sapiente rem beatae officia libero similique iste, vitae aut? Voluptatum aperiam fugit placeat adipisci,
consequatur reiciendis voluptatem eius dolore qui. Cumque delectus iste earum, explicabo error quas rerum nam!
</p>
<p>Porro tempore ipsa enim a dolore explicabo totam. Quos veniam repellendus quo excepturi voluptatibus eum
provident corrupti debitis nesciunt neque ipsa, consequatur qui illo perferendis mollitia omnis sit cum sunt.
</p>
<p>Aliquid saepe quod recusandae at adipisci veniam quasi delectus maiores magni fuga accusamus ex, facere, vero
voluptatem temporibus odit maxime. Fuga assumenda suscipit repellat sapiente, porro sit repudiandae doloremque
officiis.</p>
<h2>A continuación la firma</h2>
<img src="" alt="Firma del usuario" id="firma">
<br>
<a href="https://parzibyte.me/blog">By Parzibyte</a>
<script>
if (window.opener) {
document.querySelector("#firma").src = window.opener.obtenerImagen();
// Imprimir documento. Si no quieres imprimir, remueve la siguiente línea
window.print();
}
</script>
</body>
</html>
Es un simple documento que tiene una imagen al final. Esa imagen tiene el id firma
. Ahora quiero que te fijes en el script, mismo que se ve así:
if (window.opener) {
document.querySelector("#firma").src = window.opener.obtenerImagen();
// Imprimir documento. Si no quieres imprimir, remueve la siguiente línea
window.print();
}
Este documento no debería abrirse por sí mismo, sino que debería tener una ventana padre; para ello es la comprobación de window.opener
.
En caso de que exista ese opener
entonces obtenemos el elemento de la imagen y colocamos su src
como lo que regrese la función obtenerImagen
del padre, y después imprimimos.
Ahora veamos la función obtenerImagen
del padre, misma que se ve así:
window.obtenerImagen = () => {
return $canvas.toDataURL();
};
La ventana hija va a solicitar al padre la imagen, y como en el padre tenemos el canvas entonces simplemente le enviamos la firma del usuario en base64, misma que será colocada en la imagen.
Todo esto ya lo he explicado a detalle en mi post de comunicación entre ventanas de JavaScript.
Poniendo todo junto
Te he mostrado y explicado el código más importante para solicitar la firma del usuario y después guardarla como imagen o generarla en un documento.Ya con esto puedes crear tus propios proyectos o adaptar esto según tus necesidades.
Si quieres explorar el código completo te lo dejo en GitHub, y también te dejo una demostración en línea por aquí.
Te dejo un vídeo explicando y demostrando lo expuesto en el post: https://www.youtube.com/watch?v=c4Q_Xnd_yUM
Después puedes ver cómo mejorarlo para que funcione en móviles: https://www.youtube.com/watch?v=q47YVQa2TGM
Por cierto, puedes hacer cualquier otra cosa con la imagen. En mi blog tengo un post donde explico cómo enviar un canvas a PHP. También podrías generar el PDF directamente o imprimirlo. Todo queda en ti.
Para terminar te dejo con más tutoriales de JavaScript.
Hola,tengo un formulario en el cual unos trabajadores ponen su nombre y se llevan uniforme y se resta del stock de shetts pero me gustaria añadir la firma de cada persona en ese formulario, seria posible con este codigo
gracias
Muchas gracias por el post, me ha sido muy útil.
Una pregunta: Hay alguna manera de detectar que el canvas está vacío. me gustaría hacer esa comprobación antes de enviar la firma a la base de datos
Hola. Yo creo que sí es posible, sería cuestión de modificar el código para comprobar lo que necesita. Si tiene dudas adicionales estaré encantado de brindarle una consultoría en https://parzibyte.me/#contacto
Hola
Como se debe modificar el código para solicitar dos firmas diferentes?
Intenté hacerlo con dos archivos de js y agregando metodos iguales con nombres diferentes en un mismo js, pero no toma en cuenta ambos campos o uno o otro 🙁
Por supuesto, estaré encantado de ayudarle más a fondo. Ofrezco servicios de consultoría personalizados para resolver problemas específicos. Si está interesado, envíeme un mensaje a https://parzibyte.me/#contacto y podemos conversar sobre cómo puedo ayudarle.
Como hacer para que funcione desde una table o un celular, gracias muy amable por tu respuesta
Hola. Gracias por sus comentarios. Si tiene alguna consulta o duda, solicitud de creación de un programa o solicitud de cambio de software estoy para servirle en https://parzibyte.me/#contacto
Saludos!
Y como seria la validacion de la firma en caso de que esta sea obligatoria? como se valida que se haya firmado y que no valla en blanco
Hola. Gracias por sus comentarios. Si tiene alguna consulta, solicitud de creación de un programa o solicitud de cambio de software estoy para servirle en https://parzibyte.me/#contacto
Saludos!
Buenas,
MUY bueno el ejemplo, el caso es que necesitaría guardar el documento firmado en una Ruta en concreto, ¿ habría forma de añadir un botón para guardaren una ruta en concreto ?
Gracias,
Juan Peláez
Hola. Gracias por sus comentarios. Si tiene alguna consulta, solicitud de creación de un programa o solicitud de cambio de software estoy para servirle en https://parzibyte.me/#contacto
Saludos!
Muchas gracias por este tutorial, andaba buscando algo como esto para un app interna de mi empresa y me ha venido genial.
Pero tengo un problema, cuando le doy a generar el documento no me lleva la firma, si lo abro el inspeccionador y refresco me la trae pero como al darle a generar la firma me refresca también la otra ventana me la trae en blanco. Me puedes ayudar?
Hola. Claro, si necesita ayuda puede enviarme un mensaje en https://parzibyte.me/#contacto