98 lines
3.2 KiB
JavaScript
98 lines
3.2 KiB
JavaScript
(() => {
|
|
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"));
|
|
})(); |