From 5b2992b616aeecf0ecae74c95188e0580c738e47 Mon Sep 17 00:00:00 2001 From: Igor Zinken <730069+igorski@users.noreply.github.com> Date: Tue, 25 Mar 2025 21:24:43 +0100 Subject: [PATCH] Initial implementation --- .../document-canvas/document-canvas.vue | 4 ++ src/definitions/tool-types.ts | 2 +- src/rendering/actors/interaction-pane.ts | 46 ++++++++++++++++++- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/components/document-canvas/document-canvas.vue b/src/components/document-canvas/document-canvas.vue index 2ce9002e..10135073 100644 --- a/src/components/document-canvas/document-canvas.vue +++ b/src/components/document-canvas/document-canvas.vue @@ -434,6 +434,7 @@ export default { if ( !zCanvas ) { return; } + console.info('update interaction pane') const enabled = true; // always enabled (shows active layer outline)//this.panMode || this.layerSelectMode || this.selectMode; let mode: InteractionModes; if ( this.panMode ) { @@ -442,6 +443,9 @@ export default { mode = InteractionModes.MODE_LAYER_SELECT; } else if ( this.selectMode ) { mode = InteractionModes.MODE_SELECTION; + } else if ( this.activeTool === ToolTypes.ZOOM ) { + console.info('ohohoho, zoom zoom') + mode = InteractionModes.MODE_ZOOM; } else { return this.handleActiveTool( this.activeTool ); // likely unsetting mode through keyboard shortcut (e.g. space-pan/(de)select all) } diff --git a/src/definitions/tool-types.ts b/src/definitions/tool-types.ts index f792114c..7987fe10 100644 --- a/src/definitions/tool-types.ts +++ b/src/definitions/tool-types.ts @@ -47,7 +47,7 @@ export default ToolTypes; // certain tools are handled by the top layer interaction pane, not individual layer renderers -export const PANE_TYPES = [ ToolTypes.MOVE, ToolTypes.LASSO, ToolTypes.SELECTION, ToolTypes.WAND ]; +export const PANE_TYPES = [ ToolTypes.MOVE, ToolTypes.LASSO, ToolTypes.SELECTION, ToolTypes.WAND, ToolTypes.ZOOM ]; export const usesInteractionPane = ( tool: ToolTypes ): boolean => PANE_TYPES.includes( tool ); export const SELECTION_TOOLS = [ ToolTypes.SELECTION, ToolTypes.LASSO, ToolTypes.WAND ]; diff --git a/src/rendering/actors/interaction-pane.ts b/src/rendering/actors/interaction-pane.ts index dec44bfa..95d4218a 100644 --- a/src/rendering/actors/interaction-pane.ts +++ b/src/rendering/actors/interaction-pane.ts @@ -43,6 +43,7 @@ export enum InteractionModes { MODE_PAN = 0, MODE_LAYER_SELECT, MODE_SELECTION, + MODE_ZOOM, }; const DASH_SIZE = 10; @@ -105,7 +106,7 @@ export default class InteractionPane extends sprite { const document = this.getActiveDocument(); - if ( document && mode === InteractionModes.MODE_SELECTION ) { + if ( document && [ InteractionModes.MODE_SELECTION, InteractionModes.MODE_ZOOM ].includes( mode )) { // create empty selection (or reset to empty selection when switching between // rectangle selection tool modes) if ( !document.activeSelection ) { @@ -115,7 +116,7 @@ export default class InteractionPane extends sprite { } this._selectionClosed = isShapeClosed( getLastShape( document.activeSelection )); // we distinguish between the rectangular and lasso selection tool - this._isRectangleSelect = activeTool === ToolTypes.SELECTION; + this._isRectangleSelect = activeTool === ToolTypes.SELECTION || activeTool === ToolTypes.ZOOM; // selection mode has an always active move listener this.forceMoveListener(); } else { @@ -266,6 +267,7 @@ export default class InteractionPane extends sprite { break; case InteractionModes.MODE_SELECTION: + case InteractionModes.MODE_ZOOM: const isShiftKeyDown = KeyboardService.hasShift(); let { activeSelection } = this.getActiveDocument(); let completeSelection = false; @@ -363,6 +365,46 @@ export default class InteractionPane extends sprite { const isDoubleClick = ( now - this._lastRelease ) < 250; this._lastRelease = now; + if ( this.mode === InteractionModes.MODE_ZOOM ) { + const { width, height } = calculateSelectionSize( this._dragStartEventCoordinates, this._pointer, this._toolOptions ); + const selection = rectToCoordinateList( this._dragStartEventCoordinates.x, this._dragStartEventCoordinates.y, width, height ); + + console.info('complete die zoom, fucker!', width, height,selection); + + const scaleX = this.canvas.getViewport().width / width; + const scaleY = this.canvas.getViewport().height / height; + const scale = Math.min(scaleX, scaleY); // Maintain aspect ratio + + function calculateOffset( + selectionRect: Rectangle, + viewportSize: Viewport, + scale: number + ): { offsetX: number; offsetY: number } { + const centerX = selectionRect.x + selectionRect.width / 2; + const centerY = selectionRect.y + selectionRect.height / 2; + + const viewportCenterX = viewportSize.width / 2; + const viewportCenterY = viewportSize.height / 2; + + // Offset needs to center the selected area in the viewport + const offsetX = viewportCenterX - centerX * scale; + const offsetY = viewportCenterY - centerY * scale; + + return { offsetX, offsetY }; + } + const left = Math.min( this._dragStartEventCoordinates.x, this._pointer.x ); + const top = Math.min( this._dragStartEventCoordinates.y, this._pointer.y ); + const { offsetX, offsetY } = calculateOffset({x:left, y:top, width, height}, this.canvas.getViewport(), scale); + console.info('offset:'+offsetX + ' x ' + offsetY); + + this.canvas.store.commit( "setToolOptionValue", { + tool: ToolTypes.ZOOM, + option: "level", + value: scale, + }); + this.canvas.panViewport( offsetX, offsetY ); + } + if ( this.mode === InteractionModes.MODE_SELECTION ) { this._isAddingToExistingSelection = false; this.forceMoveListener(); // keep the move listener active