import React, { useRef, useState, useEffect } from "react";
const SignaturePad = ({ onSave, initialValue = '' }) => {
const canvasRef = useRef(null);
const containerRef = useRef(null);
const [isDrawing, setIsDrawing] = useState(false);
const [canvasSize, setCanvasSize] = useState({ width: 0, height: 200 });
// Función para actualizar el tamaño del canvas
const updateCanvasSize = () => {
if (containerRef.current) {
const containerWidth = containerRef.current.offsetWidth;
setCanvasSize({ width: containerWidth, height: 200 });
}
};
// Efecto para manejar el redimensionamiento
useEffect(() => {
updateCanvasSize();
window.addEventListener('resize', updateCanvasSize);
return () => window.removeEventListener('resize', updateCanvasSize);
}, []);
// Efecto para inicializar el canvas
useEffect(() => {
const canvas = canvasRef.current;
const ctx = canvas.getContext("2d");
ctx.lineJoin = "round";
ctx.lineCap = "round";
// Ajustar el tamaño del canvas para mantener la calidad
const dpr = window.devicePixelRatio || 1;
canvas.width = canvasSize.width * dpr;
canvas.height = canvasSize.height * dpr;
ctx.scale(dpr, dpr);
// Aplicar el tamaño visual mediante CSS
canvas.style.width = `${canvasSize.width}px`;
canvas.style.height = `${canvasSize.height}px`;
// Si hay un valor inicial, dibujarlo
if (initialValue) {
const img = new Image();
img.onload = () => {
ctx.drawImage(img, 0, 0);
};
img.src = initialValue;
}
}, [initialValue, canvasSize]);
const startDrawing = (e) => {
e.preventDefault();
const canvas = canvasRef.current;
const ctx = canvas.getContext("2d");
ctx.beginPath();
const rect = canvas.getBoundingClientRect();
const x = e.touches ? e.touches[0].clientX : e.clientX;
const y = e.touches ? e.touches[0].clientY : e.clientY;
ctx.moveTo(x - rect.left, y - rect.top);
setIsDrawing(true);
};
const draw = (e) => {
e.preventDefault();
if (!isDrawing) return;
const canvas = canvasRef.current;
const ctx = canvas.getContext("2d");
const rect = canvas.getBoundingClientRect();
const x = e.touches ? e.touches[0].clientX : e.clientX;
const y = e.touches ? e.touches[0].clientY : e.clientY;
ctx.lineTo(x - rect.left, y - rect.top);
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.stroke();
};
const stopDrawing = () => {
if (isDrawing) {
setIsDrawing(false);
saveSignature();
}
};
const clearCanvas = () => {
const canvas = canvasRef.current;
const ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
onSave("");
};
const saveSignature = () => {
const canvas = canvasRef.current;
if (isCanvasEmpty(canvas)) {
onSave("");
} else {
const dataUrl = canvas.toDataURL("image/png");
onSave(dataUrl);
}
};
const isCanvasEmpty = (canvas) => {
const ctx = canvas.getContext("2d");
const pixels = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
return !pixels.some(pixel => pixel !== 0);
};
return (
<div className="flex flex-col items-center gap-4 w-full">
<div
ref={containerRef}
className="border border-gray rounded relative w-full max-w-2xl"
>
<canvas
ref={canvasRef}
style={{
touchAction: "none",
width: '100%',
height: `${canvasSize.height}px`
}}
className="bg-white"
onMouseDown={startDrawing}
onMouseMove={draw}
onMouseUp={stopDrawing}
onMouseLeave={stopDrawing}
onTouchStart={startDrawing}
onTouchMove={draw}
onTouchEnd={stopDrawing}
/>
</div>
<button
type="button"
onClick={clearCanvas}
className="px-4 py-2 text-sm text-red-600 hover:text-red-700"
>
Limpiar firma
</button>
</div>
);
};
export default SignaturePad;