From 50dbb4e0cf9ef0e79f6ab227b291cde65404b1d4 Mon Sep 17 00:00:00 2001 From: Hiren Kangad Date: Fri, 13 Mar 2026 12:42:16 +0530 Subject: [PATCH] refboard: anchor crop apply to selected region --- frontend/src/canvas/CropOverlay.ts | 9 ++++++--- frontend/src/hooks/useCanvasSetup.ts | 7 +++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/frontend/src/canvas/CropOverlay.ts b/frontend/src/canvas/CropOverlay.ts index b6b8c9e..d44e0ac 100644 --- a/frontend/src/canvas/CropOverlay.ts +++ b/frontend/src/canvas/CropOverlay.ts @@ -38,7 +38,7 @@ export class CropOverlay extends Container { private _crop: CropRect = { x: 0, y: 0, w: 1, h: 1 }; private _originalCrop: CropRect | undefined; private _drag: { mode: DragMode; startCrop: CropRect; startPoint: { x: number; y: number } } | null = null; - private _onConfirm: ((item: SceneItem, crop: CropRect) => void) | null = null; + private _onConfirm: ((item: SceneItem, crop: CropRect, anchorWorld: { x: number; y: number }) => void) | null = null; private _onCancel: (() => void) | null = null; private _onStateChange: ((active: boolean) => void) | null = null; private _keyHandler: ((e: KeyboardEvent) => void) | null = null; @@ -84,7 +84,7 @@ export class CropOverlay extends Container { } } - set onConfirm(fn: (item: SceneItem, crop: CropRect) => void) { this._onConfirm = fn; } + set onConfirm(fn: (item: SceneItem, crop: CropRect, anchorWorld: { x: number; y: number }) => void) { this._onConfirm = fn; } set onCancel(fn: () => void) { this._onCancel = fn; } set onStateChange(fn: (active: boolean) => void) { this._onStateChange = fn; } @@ -120,9 +120,12 @@ export class CropOverlay extends Container { if (!this._item) return; const item = this._item; const crop = { ...this._crop }; + const data = item.data as ImageObject; + const viewCrop = this._getViewCrop(); + const anchorWorld = imageViewPointToWorld(data, viewCrop.x, viewCrop.y); const isFullImage = crop.x < 0.001 && crop.y < 0.001 && crop.w > 0.999 && crop.h > 0.999; this._cleanup(); - this._onConfirm?.(item, isFullImage ? { x: 0, y: 0, w: 1, h: 1 } : crop); + this._onConfirm?.(item, isFullImage ? { x: 0, y: 0, w: 1, h: 1 } : crop, anchorWorld); } /** Cancel cropping — restore original state. */ diff --git a/frontend/src/hooks/useCanvasSetup.ts b/frontend/src/hooks/useCanvasSetup.ts index 8b98630..3ee4c39 100644 --- a/frontend/src/hooks/useCanvasSetup.ts +++ b/frontend/src/hooks/useCanvasSetup.ts @@ -477,17 +477,16 @@ export function useCanvasSetup(deps: CanvasSetupDeps) { onCropModeChange?.(active); }; - cropOverlay.onConfirm = (item, crop) => { + cropOverlay.onConfirm = (item, crop, anchorWorld) => { const imgData = item.data as any; - const before = getItemWorldBounds(item); const isFullImage = crop.x < 0.001 && crop.y < 0.001 && crop.w > 0.999 && crop.h > 0.999; imgData.crop = isFullImage ? undefined : crop; if (item.displayObject instanceof ImageSprite) { item.displayObject.applyCrop(imgData.crop); } const after = getItemWorldBounds(item); - imgData.x += before.x - after.x; - imgData.y += before.y - after.y; + imgData.x += anchorWorld.x - after.x; + imgData.y += anchorWorld.y - after.y; if (item.type === 'image') { applyImageDisplayTransform(item.displayObject, imgData); }