File "firmas.js"

Full Path: C:/wamp64/www/Actas_Usuarios/assets/js/firmas.js
File size: 3.91 KB
MIME-type: text/x-c++
Charset: utf-8

// assets/js/firmas.js

class FirmaCanvas {
    constructor(canvasId, inputId, btnLimpiarId) {
        this.canvas     = document.getElementById(canvasId);
        this.ctx        = this.canvas.getContext('2d');
        this.input      = document.getElementById(inputId);
        this.btnLimpiar = document.getElementById(btnLimpiarId);
        this.dibujando  = false;

        this._init();
        this._eventos();
    }

    _init() {
        // Tomamos el ancho del CONTENEDOR padre, no del canvas
        // Así obtenemos el ancho real ya renderizado por CSS
        const contenedor = this.canvas.parentElement;
        const ancho      = contenedor.clientWidth;
        const alto       = 160;

        // Asignamos tamaño CSS primero
        this.canvas.style.width  = ancho + 'px';
        this.canvas.style.height = alto  + 'px';

        // Luego el tamaño interno del bitmap (sin multiplicar por dpr
        // para evitar el desfase de coordenadas en pantallas de alta densidad)
        this.canvas.width  = ancho;
        this.canvas.height = alto;

        this._limpiar();
    }

    _limpiar() {
        this.ctx.fillStyle   = '#ffffff';
        this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
        this.ctx.strokeStyle = '#000000';
        this.ctx.lineWidth   = 2.5;
        this.ctx.lineCap     = 'round';
        this.ctx.lineJoin    = 'round';
        this.input.value     = '';
    }

    // Posición exacta relativa al canvas, corregida para zoom y scroll
    _pos(e) {
        const rect = this.canvas.getBoundingClientRect();
        const src  = e.touches ? e.touches[0] : e;

        // scaleX/scaleY corrige si el canvas CSS != tamaño interno del bitmap
        const scaleX = this.canvas.width  / rect.width;
        const scaleY = this.canvas.height / rect.height;

        return {
            x: (src.clientX - rect.left) * scaleX,
            y: (src.clientY - rect.top)  * scaleY
        };
    }

    _start(e) {
        this.dibujando = true;
        const p = this._pos(e);
        this.ctx.beginPath();
        this.ctx.moveTo(p.x, p.y);
        e.preventDefault();
    }

    _move(e) {
        if (!this.dibujando) return;
        const p = this._pos(e);
        this.ctx.lineTo(p.x, p.y);
        this.ctx.stroke();
        e.preventDefault();
    }

    _end(e) {
        if (this.dibujando) {
            this.dibujando   = false;
            this.input.value = this.canvas.toDataURL('image/png');
        }
        e.preventDefault();
    }

    _eventos() {
        ['mousedown', 'touchstart'].forEach(ev =>
            this.canvas.addEventListener(ev, e => this._start(e), { passive: false }));

        ['mousemove', 'touchmove'].forEach(ev =>
            this.canvas.addEventListener(ev, e => this._move(e), { passive: false }));

        ['mouseup', 'mouseleave', 'touchend', 'touchcancel'].forEach(ev =>
            this.canvas.addEventListener(ev, e => this._end(e), { passive: false }));

        this.btnLimpiar?.addEventListener('click', () => this._limpiar());
    }
}

// ── Inicialización ───────────────────────────────────────────────────────
document.addEventListener('DOMContentLoaded', () => {

    new FirmaCanvas('canvasEntrega', 'firma_entrega', 'limpiar_entrega');
    new FirmaCanvas('canvasRecibe',  'firma_recibe',  'limpiar_recibe');

    // Validación antes de enviar
    document.getElementById('form_acta')?.addEventListener('submit', e => {
        const fEntrega = document.getElementById('firma_entrega').value;
        const fRecibe  = document.getElementById('firma_recibe').value;

        if (!fEntrega) {
            e.preventDefault();
            alert('⚠️ Debe dibujar la firma de quien entrega.');
            return;
        }
        if (!fRecibe) {
            e.preventDefault();
            alert('⚠️ Debe dibujar la firma de quien recibe.');
        }
    });
});