feat: add shift+drag to manually mark redaction boxes

Hold Shift and drag on the canvas to draw a custom redaction
rectangle. Creates an unanalyzed redaction entry that triggers
on-demand OCR when clicked.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
This commit is contained in:
Alex-GilbertandClaude Opus 4.6 committed 2026-02-16 14:47:36 -06:00
1 parent 5f2e1c5ec9
commit a481608d41
1 file changed
+75
+75
View File
@@ -1036,6 +1036,81 @@ function showAssocDetail(assocMatches, anchorEl) {
setTimeout(() => document.addEventListener("click", closeOnOutside, true), 0);
}
// ── Manual redaction marking (Shift+drag) ──
let drawDrag = null;
canvas.addEventListener("mousedown", (e) => {
if (!e.shiftKey || e.button !== 0) return;
const rect = rightPanel.getBoundingClientRect();
const sx = e.clientX - rect.left;
const sy = e.clientY - rect.top;
const doc = screenToDoc(sx, sy);
drawDrag = { startX: doc.x, startY: doc.y };
e.stopPropagation();
e.preventDefault();
}, { capture: true }); // capture so it fires before the regular hit-test handler
window.addEventListener("mousemove", (e) => {
if (!drawDrag) return;
const rect = rightPanel.getBoundingClientRect();
const sx = e.clientX - rect.left;
const sy = e.clientY - rect.top;
const doc = screenToDoc(sx, sy);
// Re-render canvas with a preview rectangle
renderCanvas();
const x = Math.min(drawDrag.startX, doc.x);
const y = Math.min(drawDrag.startY, doc.y);
const w = Math.abs(doc.x - drawDrag.startX);
const h = Math.abs(doc.y - drawDrag.startY);
ctx.strokeStyle = "rgba(255, 100, 100, 0.8)";
ctx.lineWidth = 2;
ctx.setLineDash([6, 3]);
ctx.strokeRect(x, y, w, h);
ctx.setLineDash([]);
});
window.addEventListener("mouseup", (e) => {
if (!drawDrag) return;
const rect = rightPanel.getBoundingClientRect();
const sx = e.clientX - rect.left;
const sy = e.clientY - rect.top;
const doc = screenToDoc(sx, sy);
const x = Math.round(Math.min(drawDrag.startX, doc.x));
const y = Math.round(Math.min(drawDrag.startY, doc.y));
const w = Math.round(Math.abs(doc.x - drawDrag.startX));
const h = Math.round(Math.abs(doc.y - drawDrag.startY));
drawDrag = null;
// Only create if large enough
if (w < 20 || h < 5) {
renderCanvas();
return;
}
const id = "m" + Date.now().toString(36);
state.redactions[id] = {
id, x, y, w, h,
page: state.currentPage,
status: "unanalyzed",
analysis: null,
solution: null,
preview: null,
};
renderRedactionList();
renderCanvas();
activateRedaction(id);
});
// ── Utility ──
function escapeHtml(text) {