From c6c3bbc0240e4e6cf5ba49d09fcffa6b8b987b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Kr=C4=8Dek?= Date: Mon, 8 Sep 2025 15:19:05 +0200 Subject: [PATCH] Fix manual resizing --- .../wizard/subcomponents/PhotoCrop.svelte | 195 +++++++----------- 1 file changed, 73 insertions(+), 122 deletions(-) diff --git a/src/lib/components/wizard/subcomponents/PhotoCrop.svelte b/src/lib/components/wizard/subcomponents/PhotoCrop.svelte index 6d47b97..bd1a8dc 100644 --- a/src/lib/components/wizard/subcomponents/PhotoCrop.svelte +++ b/src/lib/components/wizard/subcomponents/PhotoCrop.svelte @@ -35,9 +35,7 @@ // Interaction state let isDragging = false; - let isResizing = false; let dragStart = { x: 0, y: 0 }; - let resizeHandle = ''; // Canvas dimensions let canvasWidth = 600; @@ -135,25 +133,6 @@ ctx.strokeStyle = '#3b82f6'; ctx.lineWidth = 2; ctx.strokeRect(crop.x, crop.y, crop.width, crop.height); - - // Draw resize handles - const handleSize = 12; // Increased from 8 for easier grabbing - ctx.fillStyle = '#3b82f6'; - ctx.strokeStyle = '#ffffff'; - ctx.lineWidth = 1; - - // Corner handles with white borders for better visibility - const handles = [ - { x: crop.x - handleSize/2, y: crop.y - handleSize/2, cursor: 'nw-resize' }, - { x: crop.x + crop.width - handleSize/2, y: crop.y - handleSize/2, cursor: 'ne-resize' }, - { x: crop.x - handleSize/2, y: crop.y + crop.height - handleSize/2, cursor: 'sw-resize' }, - { x: crop.x + crop.width - handleSize/2, y: crop.y + crop.height - handleSize/2, cursor: 'se-resize' }, - ]; - - handles.forEach(handle => { - ctx.fillRect(handle.x, handle.y, handleSize, handleSize); - ctx.strokeRect(handle.x, handle.y, handleSize, handleSize); - }); } function getMousePos(e: MouseEvent) { @@ -165,31 +144,12 @@ } function isInCropArea(x: number, y: number) { - return x >= crop.x && x <= crop.x + crop.width && - y >= crop.y && y <= crop.y + crop.height; - } - - function getResizeHandle(x: number, y: number) { - const handleSize = 12; // Match the drawing size - const tolerance = handleSize; - - if (Math.abs(x - crop.x) <= tolerance && Math.abs(y - crop.y) <= tolerance) return 'nw'; - if (Math.abs(x - (crop.x + crop.width)) <= tolerance && Math.abs(y - crop.y) <= tolerance) return 'ne'; - if (Math.abs(x - crop.x) <= tolerance && Math.abs(y - (crop.y + crop.height)) <= tolerance) return 'sw'; - if (Math.abs(x - (crop.x + crop.width)) <= tolerance && Math.abs(y - (crop.y + crop.height)) <= tolerance) return 'se'; - - return ''; + return x >= crop.x && x <= crop.x + crop.width && y >= crop.y && y <= crop.y + crop.height; } function handleMouseDown(e: MouseEvent) { const pos = getMousePos(e); - const handle = getResizeHandle(pos.x, pos.y); - - if (handle) { - isResizing = true; - resizeHandle = handle; - dragStart = pos; - } else if (isInCropArea(pos.x, pos.y)) { + if (isInCropArea(pos.x, pos.y)) { isDragging = true; dragStart = { x: pos.x - crop.x, y: pos.y - crop.y }; } @@ -197,87 +157,14 @@ function handleMouseMove(e: MouseEvent) { const pos = getMousePos(e); - - if (isResizing) { - const dx = pos.x - dragStart.x; - const dy = pos.y - dragStart.y; - - const newCrop = { ...crop }; - - // Use primary axis movement for more predictable resizing - switch (resizeHandle) { - case 'nw': - // Use the dominant movement direction - const primaryDelta = Math.abs(dx) > Math.abs(dy) ? dx : dy * cropRatio; - const newWidth = Math.max(20, crop.width - primaryDelta); - const newHeight = newWidth / cropRatio; - - newCrop.x = Math.max(0, crop.x + crop.width - newWidth); - newCrop.y = Math.max(0, crop.y + crop.height - newHeight); - newCrop.width = newWidth; - newCrop.height = newHeight; - break; - - case 'ne': - // For NE, primarily follow horizontal movement - const newWidthNE = Math.max(20, crop.width + dx); - const newHeightNE = newWidthNE / cropRatio; - - newCrop.width = newWidthNE; - newCrop.height = newHeightNE; - newCrop.y = Math.max(0, crop.y + crop.height - newHeightNE); - break; - - case 'sw': - // For SW, primarily follow horizontal movement - const newWidthSW = Math.max(20, crop.width - dx); - const newHeightSW = newWidthSW / cropRatio; - - newCrop.x = Math.max(0, crop.x + crop.width - newWidthSW); - newCrop.width = newWidthSW; - newCrop.height = newHeightSW; - break; - - case 'se': - // For SE, primarily follow horizontal movement - const newWidthSE = Math.max(20, crop.width + dx); - const newHeightSE = newWidthSE / cropRatio; - - newCrop.width = newWidthSE; - newCrop.height = newHeightSE; - break; - } - - // Ensure crop stays within canvas bounds - if (newCrop.x + newCrop.width > canvasWidth) { - newCrop.width = canvasWidth - newCrop.x; - newCrop.height = newCrop.width / cropRatio; - } - if (newCrop.y + newCrop.height > canvasHeight) { - newCrop.height = canvasHeight - newCrop.y; - newCrop.width = newCrop.height * cropRatio; - } - - // Adjust position if crop extends beyond bounds after resizing - if (newCrop.x + newCrop.width > canvasWidth) { - newCrop.x = canvasWidth - newCrop.width; - } - if (newCrop.y + newCrop.height > canvasHeight) { - newCrop.y = canvasHeight - newCrop.height; - } - - crop = newCrop; - drawCanvas(); - } else if (isDragging) { + + if (isDragging) { crop.x = Math.max(0, Math.min(canvasWidth - crop.width, pos.x - dragStart.x)); crop.y = Math.max(0, Math.min(canvasHeight - crop.height, pos.y - dragStart.y)); drawCanvas(); } else { // Update cursor based on hover state - const handle = getResizeHandle(pos.x, pos.y); - if (handle) { - canvas.style.cursor = handle + '-resize'; - } else if (isInCropArea(pos.x, pos.y)) { + if (isInCropArea(pos.x, pos.y)) { canvas.style.cursor = 'move'; } else { canvas.style.cursor = 'default'; @@ -287,11 +174,39 @@ function handleMouseUp() { isDragging = false; - isResizing = false; - resizeHandle = ''; canvas.style.cursor = 'default'; } + function zoom(factor: number) { + const center = { + x: crop.x + crop.width / 2, + y: crop.y + crop.height / 2 + }; + + let newWidth = crop.width * factor; + let newHeight = newWidth / cropRatio; + + // Clamp to min/max size + newWidth = Math.max(20, Math.min(canvasWidth, newWidth)); + newHeight = newWidth / cropRatio; + + if (newHeight > canvasHeight) { + newHeight = canvasHeight; + newWidth = newHeight * cropRatio; + } + + crop.width = newWidth; + crop.height = newHeight; + crop.x = center.x - newWidth / 2; + crop.y = center.y - newHeight / 2; + + // Ensure it stays within bounds after zooming + crop.x = Math.max(0, Math.min(canvasWidth - crop.width, crop.x)); + crop.y = Math.max(0, Math.min(canvasHeight - crop.height, crop.y)); + + drawCanvas(); + } + function handleSave() { // Scale crop rectangle back to original image dimensions const scaleX = image.width / canvasWidth; @@ -352,16 +267,52 @@ -
+
+
+ + +