ProyectoDishjer / clienteapp-frontend / src / components / firmaCanvas.js
firmaCanvas.js
Raw
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;