snap edges on crop
All checks were successful
Build Images and Deploy / Update-PROD-Stack (push) Successful in 1m10s

This commit is contained in:
2026-02-09 22:42:36 -05:00
parent d94b2d6ab8
commit 8a5822e556

View File

@@ -544,7 +544,7 @@
<div class="form-group"> <div class="form-group">
<label>✂️ Crop Video</label> <label>✂️ Crop Video</label>
<p style="font-size: 0.9em; color: #6c757d; margin-bottom: 10px;"> <p style="font-size: 0.9em; color: #6c757d; margin-bottom: 10px;">
💡 Draw crop area on video above • Double-click corner handles to snap to edges 💡 Draw crop area on video above • Double-click edges or corners to snap
</p> </p>
<div class="crop-controls"> <div class="crop-controls">
<div class="form-row"> <div class="form-row">
@@ -942,6 +942,16 @@
const mouseX = e.clientX - rect.left; const mouseX = e.clientX - rect.left;
const mouseY = e.clientY - rect.top; const mouseY = e.clientY - rect.top;
// Check for edge click first (between corners)
const edge = getEdgeAtPosition(mouseX, mouseY);
if (edge) {
snapEdgeToSide(edge);
updateFormFields();
drawCropRect();
return;
}
// Fall back to corner handling
const handle = getHandleAtPosition(mouseX, mouseY); const handle = getHandleAtPosition(mouseX, mouseY);
if (handle) { if (handle) {
snapHandleToEdge(handle); snapHandleToEdge(handle);
@@ -1017,6 +1027,39 @@
return null; return null;
} }
function getEdgeAtPosition(x, y) {
if (!cropRect) return null;
const tolerance = 15; // Click detection tolerance in pixels
const { x: rx, y: ry, width: rw, height: rh } = cropRect;
// Check if within the rectangle bounds (with tolerance)
const inHorizontalRange = x >= rx - tolerance && x <= rx + rw + tolerance;
const inVerticalRange = y >= ry - tolerance && y <= ry + rh + tolerance;
// Top edge (exclude corners)
if (Math.abs(y - ry) <= tolerance && x > rx + handleSize && x < rx + rw - handleSize) {
return 'top';
}
// Bottom edge (exclude corners)
if (Math.abs(y - (ry + rh)) <= tolerance && x > rx + handleSize && x < rx + rw - handleSize) {
return 'bottom';
}
// Left edge (exclude corners)
if (Math.abs(x - rx) <= tolerance && y > ry + handleSize && y < ry + rh - handleSize) {
return 'left';
}
// Right edge (exclude corners)
if (Math.abs(x - (rx + rw)) <= tolerance && y > ry + handleSize && y < ry + rh - handleSize) {
return 'right';
}
return null;
}
function getHandleCursor(handle) { function getHandleCursor(handle) {
const cursors = { const cursors = {
'tl': 'nw-resize', 'tl': 'nw-resize',
@@ -1122,6 +1165,27 @@
} }
} }
function snapEdgeToSide(edge) {
if (!cropRect) return;
switch (edge) {
case 'top': // Snap top edge to y=0
cropRect.height += cropRect.y; // Extend height by current y
cropRect.y = 0;
break;
case 'bottom': // Snap bottom edge to canvas height
cropRect.height = cropCanvas.height - cropRect.y;
break;
case 'left': // Snap left edge to x=0
cropRect.width += cropRect.x; // Extend width by current x
cropRect.x = 0;
break;
case 'right': // Snap right edge to canvas width
cropRect.width = cropCanvas.width - cropRect.x;
break;
}
}
function updateFormFields() { function updateFormFields() {
if (!cropRect) return; if (!cropRect) return;