V1.0
This commit is contained in:
300
js/signature.js
Normal file
300
js/signature.js
Normal file
@@ -0,0 +1,300 @@
|
||||
// Configure pdf.js worker
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
|
||||
|
||||
const canvas = document.getElementById('signatureCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
let isDrawing = false;
|
||||
let hasSignature = false;
|
||||
let ws = null;
|
||||
let currentPdf = null;
|
||||
let pdfDoc = null;
|
||||
let currentPageNum = 1;
|
||||
let totalPages = 1;
|
||||
|
||||
connectWebSocket();
|
||||
|
||||
function connectWebSocket() {
|
||||
// Use current host (works for localhost, IP addresses, and reverse proxy)
|
||||
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
const wsHost = window.location.hostname;
|
||||
// If using HTTPS (reverse proxy), use same port as page (usually 443, no port needed)
|
||||
// If using HTTP directly, use port 8080
|
||||
const wsPort = window.location.protocol === 'https:' ? '' : ':8080';
|
||||
const wsUrl = `${wsProtocol}//${wsHost}${wsPort}`;
|
||||
console.log('Verbinde WebSocket zu:', wsUrl);
|
||||
ws = new WebSocket(wsUrl);
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('WebSocket verbunden');
|
||||
document.getElementById('loadingSection').style.display = 'none';
|
||||
document.getElementById('waitingSection').style.display = 'block';
|
||||
|
||||
// Register as signature station
|
||||
ws.send(JSON.stringify({
|
||||
type: 'register_signature'
|
||||
}));
|
||||
};
|
||||
|
||||
ws.onmessage = async (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
if (data.type === 'pdf') {
|
||||
console.log('PDF empfangen');
|
||||
currentPdf = new Uint8Array(data.pdf);
|
||||
|
||||
// Show PDF notification
|
||||
document.getElementById('waitingSection').style.display = 'none';
|
||||
document.getElementById('signatureSection').style.display = 'block';
|
||||
document.getElementById('pdfDisplay').classList.add('show');
|
||||
|
||||
// Render ALL pages of PDF
|
||||
await renderPdfPreview(currentPdf);
|
||||
|
||||
// Clear previous signature if any
|
||||
clearSignature();
|
||||
} else if (data.type === 'page_change') {
|
||||
currentPageNum = data.pageNum;
|
||||
totalPages = data.totalPages;
|
||||
|
||||
// Scroll to the specific page
|
||||
const pageCanvas = document.getElementById(`page-canvas-${data.pageNum}`);
|
||||
if (pageCanvas) {
|
||||
pageCanvas.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
} else if (data.type === 'signature_placed') {
|
||||
console.log('✅ Unterschrift wurde platziert! Reset in 5 Sekunden...');
|
||||
console.log('Empfangene Daten:', JSON.stringify(data));
|
||||
|
||||
// Show immediate feedback
|
||||
const successMsg = document.getElementById('successMessage');
|
||||
successMsg.classList.add('show');
|
||||
|
||||
// Reset after 5 seconds
|
||||
setTimeout(() => {
|
||||
console.log('Auto-Reset wird durchgeführt...');
|
||||
|
||||
// Clear signature
|
||||
clearSignature();
|
||||
|
||||
// Hide success message
|
||||
document.getElementById('successMessage').classList.remove('show');
|
||||
|
||||
// Hide PDF and signature section, show waiting
|
||||
document.getElementById('signatureSection').style.display = 'none';
|
||||
document.getElementById('pdfDisplay').classList.remove('show');
|
||||
document.getElementById('waitingSection').style.display = 'block';
|
||||
|
||||
// Reset PDF data
|
||||
currentPdf = null;
|
||||
pdfDoc = null;
|
||||
currentPageNum = 1;
|
||||
totalPages = 1;
|
||||
|
||||
console.log('Bereit für nächste Unterschrift');
|
||||
}, 5000);
|
||||
} else if (data.type === 'discard') {
|
||||
console.log('🔄 Verwerfen-Nachricht empfangen, setze zurück...');
|
||||
resetSignatureStation();
|
||||
}
|
||||
};
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('WebSocket Fehler:', error);
|
||||
document.getElementById('loadingSection').innerHTML =
|
||||
'<p style="color: #dc3545;">❌ Verbindung zum Server fehlgeschlagen.</p>';
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
console.log('WebSocket getrennt');
|
||||
setTimeout(connectWebSocket, 1000);
|
||||
};
|
||||
}
|
||||
|
||||
async function renderPdfPreview(pdfBytes, pageNum = null) {
|
||||
try {
|
||||
// Create fresh copy to prevent detachment
|
||||
const safeCopy = new Uint8Array(pdfBytes.buffer.slice(0));
|
||||
|
||||
console.log('renderPdfPreview aufgerufen mit', pdfBytes.length, 'bytes');
|
||||
const loadingTask = pdfjsLib.getDocument({ data: safeCopy });
|
||||
pdfDoc = await loadingTask.promise;
|
||||
totalPages = pdfDoc.numPages;
|
||||
|
||||
// Update page info
|
||||
document.getElementById('pageInfoSignature').textContent = `${totalPages} Seite${totalPages > 1 ? 'n' : ''}`;
|
||||
|
||||
// Get container
|
||||
const container = document.getElementById('pdfPagesContainer');
|
||||
container.innerHTML = ''; // Clear existing content
|
||||
|
||||
// Render all pages
|
||||
for (let pageNum = 1; pageNum <= totalPages; pageNum++) {
|
||||
|
||||
// Add page separator if not first page
|
||||
if (pageNum > 1) {
|
||||
const separator = document.createElement('div');
|
||||
separator.className = 'page-separator';
|
||||
separator.textContent = `Seite ${pageNum}`;
|
||||
container.appendChild(separator);
|
||||
} else {
|
||||
// First page indicator
|
||||
const separator = document.createElement('div');
|
||||
separator.className = 'page-separator';
|
||||
separator.textContent = `Seite 1`;
|
||||
container.appendChild(separator);
|
||||
}
|
||||
|
||||
// Create canvas for this page
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.className = 'pdf-preview-canvas';
|
||||
canvas.id = `page-canvas-${pageNum}`;
|
||||
container.appendChild(canvas);
|
||||
|
||||
// Render page
|
||||
const page = await pdfDoc.getPage(pageNum);
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
const viewport = page.getViewport({ scale: 1.2 });
|
||||
canvas.width = viewport.width;
|
||||
canvas.height = viewport.height;
|
||||
|
||||
const renderContext = {
|
||||
canvasContext: ctx,
|
||||
viewport: viewport
|
||||
};
|
||||
|
||||
await page.render(renderContext).promise;
|
||||
}
|
||||
|
||||
console.log('Alle', totalPages, 'Seiten erfolgreich gerendert');
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Rendern der PDF Vorschau:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Canvas setup
|
||||
ctx.strokeStyle = '#000';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.lineCap = 'round';
|
||||
ctx.lineJoin = 'round';
|
||||
|
||||
function startDrawing(e) {
|
||||
isDrawing = true;
|
||||
const pos = getPosition(e);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(pos.x, pos.y);
|
||||
}
|
||||
|
||||
function draw(e) {
|
||||
if (!isDrawing) return;
|
||||
e.preventDefault();
|
||||
|
||||
const pos = getPosition(e);
|
||||
ctx.lineTo(pos.x, pos.y);
|
||||
ctx.stroke();
|
||||
|
||||
hasSignature = true;
|
||||
document.getElementById('submitButton').disabled = false;
|
||||
}
|
||||
|
||||
function stopDrawing() {
|
||||
isDrawing = false;
|
||||
}
|
||||
|
||||
function getPosition(e) {
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const scaleX = canvas.width / rect.width;
|
||||
const scaleY = canvas.height / rect.height;
|
||||
|
||||
if (e.touches && e.touches.length > 0) {
|
||||
return {
|
||||
x: (e.touches[0].clientX - rect.left) * scaleX,
|
||||
y: (e.touches[0].clientY - rect.top) * scaleY
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
x: (e.clientX - rect.left) * scaleX,
|
||||
y: (e.clientY - rect.top) * scaleY
|
||||
};
|
||||
}
|
||||
|
||||
// Mouse events
|
||||
canvas.addEventListener('mousedown', startDrawing);
|
||||
canvas.addEventListener('mousemove', draw);
|
||||
canvas.addEventListener('mouseup', stopDrawing);
|
||||
canvas.addEventListener('mouseout', stopDrawing);
|
||||
|
||||
// Touch events
|
||||
canvas.addEventListener('touchstart', startDrawing);
|
||||
canvas.addEventListener('touchmove', draw);
|
||||
canvas.addEventListener('touchend', stopDrawing);
|
||||
|
||||
// Clear button
|
||||
document.getElementById('clearButton').addEventListener('click', () => {
|
||||
clearSignature();
|
||||
});
|
||||
|
||||
function clearSignature() {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
hasSignature = false;
|
||||
document.getElementById('submitButton').disabled = true;
|
||||
document.getElementById('successMessage').classList.remove('show');
|
||||
document.getElementById('errorMessage').classList.remove('show');
|
||||
}
|
||||
|
||||
function resetSignatureStation() {
|
||||
console.log('=== SIGNATUR-STATION ZURÜCKSETZEN ===');
|
||||
|
||||
// Clear signature canvas
|
||||
clearSignature();
|
||||
|
||||
// Hide success and error messages
|
||||
document.getElementById('successMessage').classList.remove('show');
|
||||
document.getElementById('errorMessage').classList.remove('show');
|
||||
|
||||
// Hide PDF and signature section, show waiting
|
||||
document.getElementById('signatureSection').style.display = 'none';
|
||||
document.getElementById('pdfDisplay').classList.remove('show');
|
||||
document.getElementById('waitingSection').style.display = 'block';
|
||||
|
||||
// Clear PDF pages container
|
||||
const container = document.getElementById('pdfPagesContainer');
|
||||
if (container) {
|
||||
container.innerHTML = '';
|
||||
}
|
||||
|
||||
// Reset PDF data
|
||||
currentPdf = null;
|
||||
pdfDoc = null;
|
||||
currentPageNum = 1;
|
||||
totalPages = 1;
|
||||
|
||||
console.log('Signatur-Station zurückgesetzt - bereit für neue PDF');
|
||||
}
|
||||
|
||||
// Submit button
|
||||
document.getElementById('submitButton').addEventListener('click', async () => {
|
||||
if (!hasSignature || !ws || ws.readyState !== WebSocket.OPEN) return;
|
||||
|
||||
try {
|
||||
// Get signature as data URL
|
||||
const signatureDataUrl = canvas.toDataURL('image/png');
|
||||
|
||||
// Send to server (no session ID needed)
|
||||
ws.send(JSON.stringify({
|
||||
type: 'signature',
|
||||
signature: signatureDataUrl
|
||||
}));
|
||||
|
||||
// Show success message
|
||||
document.getElementById('successMessage').classList.add('show');
|
||||
document.getElementById('submitButton').disabled = true;
|
||||
|
||||
console.log('Unterschrift gesendet, warte auf Platzierungs-Bestätigung...');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Senden:', error);
|
||||
document.getElementById('errorMessage').classList.add('show');
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user