(() => { const canvas = document.getElementById("pad"); const context = canvas.getContext("2d"); const userId = document.getElementById("user-id"); const status = document.getElementById("status"); const points = []; let drawing = false; let startTime = 0; context.lineWidth = 3; context.lineCap = "round"; context.lineJoin = "round"; function pointFrom(event, penDown) { const bounds = canvas.getBoundingClientRect(); const scaleX = canvas.width / bounds.width; const scaleY = canvas.height / bounds.height; return { t: performance.now() - startTime, x: (event.clientX - bounds.left) * scaleX, y: (event.clientY - bounds.top) * scaleY, p: event.pressure || (penDown ? 0.5 : 0), area: event.width * event.height, pen_down: penDown, }; } canvas.addEventListener("pointerdown", (event) => { event.preventDefault(); canvas.setPointerCapture(event.pointerId); if (points.length === 0) startTime = performance.now(); drawing = true; const point = pointFrom(event, true); points.push(point); context.beginPath(); context.moveTo(point.x, point.y); }); canvas.addEventListener("pointermove", (event) => { if (!drawing) return; const point = pointFrom(event, true); points.push(point); context.lineTo(point.x, point.y); context.stroke(); }); function endStroke(event) { if (!drawing) return; points.push(pointFrom(event, false)); drawing = false; } canvas.addEventListener("pointerup", endStroke); canvas.addEventListener("pointercancel", endStroke); document.getElementById("clear").addEventListener("click", () => { points.length = 0; context.clearRect(0, 0, canvas.width, canvas.height); status.textContent = "Signature cleared."; }); async function send(path) { if (!userId.value.trim()) { status.textContent = "Enter a participant ID first."; return; } if (points.filter((point) => point.pen_down).length < 2) { status.textContent = "Draw a signature with at least two points."; return; } const payload = { user_id: userId.value.trim(), t: points.map((point) => point.t), x: points.map((point) => point.x), y: points.map((point) => point.y), p: points.map((point) => point.p), area: points.map((point) => point.area), pen_down: points.map((point) => point.pen_down), }; status.textContent = "Sending…"; try { const response = await fetch(path, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); const result = await response.json(); if (!response.ok) throw new Error(result.detail || `Request failed (${response.status})`); status.textContent = path === "/verify" ? `Accepted: ${result.accepted}; score: ${result.score.toFixed(3)}; threshold: ${result.threshold.toFixed(3)}` : `Enrolled sample for ${result.user_id}. Enroll multiple genuine samples.`; } catch (error) { status.textContent = `Error: ${error.message}`; } } document.getElementById("enroll").addEventListener("click", () => send("/enroll")); document.getElementById("verify").addEventListener("click", () => send("/verify")); })();