diff --git a/packages/core/src/ref_line.ts b/packages/core/src/ref_line.ts index fc743053..29dfa5b0 100644 --- a/packages/core/src/ref_line.ts +++ b/packages/core/src/ref_line.ts @@ -48,7 +48,10 @@ export class RefLine { constructor(private editor: SuikaEditor) {} - cacheXYToBbox() { + /** + * cache reference line of graphics in viewport + */ + cacheGraphicsRefLines() { this.clear(); const vRefLineMap = this.vRefLineMap; @@ -100,9 +103,9 @@ export class RefLine { } // bbox 中水平线 - this.addBboxToMap(vRefLineMap, bbox.midX, [bbox.minY, bbox.maxY]); + RefLine.addRefLinesToMap(vRefLineMap, bbox.midX, [bbox.minY, bbox.maxY]); // bbox 中垂直线 - this.addBboxToMap(hRefLineMap, bbox.midY, [bbox.minX, bbox.maxX]); + RefLine.addRefLinesToMap(hRefLineMap, bbox.midY, [bbox.minX, bbox.maxX]); /** * 获取旋转后4个顶点的坐标 @@ -141,11 +144,11 @@ export class RefLine { // top 和 bottom 要绘制水平参考线,不要绘制垂直参照线 for (const p of [...top, ...bottom]) { - this.addBboxToMap(vRefLineMap, p.x, [p.y]); + RefLine.addRefLinesToMap(vRefLineMap, p.x, [p.y]); } // left 和 right 要绘制垂直参照线,不要绘制水平参照线 for (const p of [...left, ...right]) { - this.addBboxToMap(hRefLineMap, p.y, [p.x]); + RefLine.addRefLinesToMap(hRefLineMap, p.y, [p.x]); } } @@ -160,7 +163,7 @@ export class RefLine { this.toDrawVLines = []; this.toDrawHLines = []; } - private addBboxToMap( + static addRefLinesToMap( m: Map>, xOrY: number, xsOrYs: number[], @@ -175,7 +178,7 @@ export class RefLine { } } - private getTargetPointFromSelect(record: Map) { + static getGraphicsTargetPoints(record: Map) { let targetPoints: IPoint[] = []; // 选中的为单个图形,要以旋转后的 4 个顶点和中心点为目标线 if (record.size === 1) { @@ -213,12 +216,7 @@ export class RefLine { * update ref line * and return offset */ - updateRefLine(record: Map): { - offsetX: number; - offsetY: number; - } { - const targetPoints = this.getTargetPointFromSelect(record); - + getGraphicsSnapOffset(targetPoints: IPoint[]): IPoint | undefined { this.toDrawVLines = []; this.toDrawHLines = []; @@ -234,7 +232,7 @@ export class RefLine { // there are no reference graphs if (sortedXs.length === 0 && sortedYs.length === 0) { - return { offsetX: 0, offsetY: 0 }; + return undefined; } let offsetX: number | undefined = undefined; @@ -334,7 +332,7 @@ export class RefLine { }); } - return { offsetX: offsetX ?? 0, offsetY: offsetY ?? 0 }; + return { x: offsetX ?? 0, y: offsetY ?? 0 }; } drawRefLine(ctx: CanvasRenderingContext2D) { diff --git a/packages/core/src/tools/tool_draw_graphics.ts b/packages/core/src/tools/tool_draw_graphics.ts index 2fc39eaf..21253264 100644 --- a/packages/core/src/tools/tool_draw_graphics.ts +++ b/packages/core/src/tools/tool_draw_graphics.ts @@ -55,6 +55,14 @@ export abstract class DrawGraphicsTool implements ITool { }; hotkeysManager.on('shiftToggle', updateRect); + const updateRefLinesWhenViewportTranslate = () => { + if (editor.hostEventManager.isDraggingCanvasBySpace) { + return; + } + if (this.isDragging) { + this.editor.refLine.cacheGraphicsRefLines(); + } + }; const updateRectWhenViewportTranslate = () => { if (editor.hostEventManager.isDraggingCanvasBySpace) { return; @@ -68,10 +76,18 @@ export abstract class DrawGraphicsTool implements ITool { this.updateRect(); } }; + editor.viewportManager.on( + 'xOrYChange', + updateRefLinesWhenViewportTranslate, + ); editor.viewportManager.on('xOrYChange', updateRectWhenViewportTranslate); this.unbindEvent = () => { hotkeysManager.off('shiftToggle', updateRect); + editor.viewportManager.off( + 'xOrYChange', + updateRefLinesWhenViewportTranslate, + ); editor.viewportManager.off('xOrYChange', updateRectWhenViewportTranslate); }; } @@ -117,13 +133,27 @@ export abstract class DrawGraphicsTool implements ITool { if (this.editor.hostEventManager.isDraggingCanvasBySpace) { return; } - this.isDragging = true; this.lastDragPointInViewport = this.editor.getCursorXY(e); this.lastDragPoint = this.lastMousePoint = SnapHelper.getSnapPtBySetting( this.editor.getSceneCursorXY(e), this.editor.setting, ); + + if (!this.isDragging) { + this.editor.refLine.cacheGraphicsRefLines(); + } + const offset = this.editor.refLine.getGraphicsSnapOffset([ + this.lastDragPoint, + ]); + if (offset) { + this.lastDragPoint = { + x: this.lastDragPoint.x + offset.x, + y: this.lastDragPoint.y + offset.y, + }; + } + this.isDragging = true; + this.updateRect(); } /** @@ -346,5 +376,6 @@ export abstract class DrawGraphicsTool implements ITool { } this.startPointWhenSpaceDown = null; this.lastDragPointWhenSpaceDown = null; + this.editor.refLine.clear(); } } diff --git a/packages/core/src/tools/tool_select/tool_select_move.ts b/packages/core/src/tools/tool_select/tool_select_move.ts index 6f61637a..1b40812b 100644 --- a/packages/core/src/tools/tool_select/tool_select_move.ts +++ b/packages/core/src/tools/tool_select/tool_select_move.ts @@ -9,6 +9,7 @@ import { type SuikaGraphics, } from '../../graphics'; import { type SuikaCanvas } from '../../graphics/canvas'; +import { RefLine } from '../../ref_line'; import { Transaction } from '../../transaction'; import { getDeepFrameAtPoint } from '../../utils'; import { type IBaseTool } from '../type'; @@ -85,7 +86,7 @@ export class SelectMoveTool implements IBaseTool { this.prevBBoxPos = { x: boundingRect.x, y: boundingRect.y }; } - this.editor.refLine.cacheXYToBbox(); + this.editor.refLine.cacheGraphicsRefLines(); } onDrag(e: PointerEvent) { this.dragPoint = this.editor.getCursorXY(e); @@ -141,7 +142,8 @@ export class SelectMoveTool implements IBaseTool { }); } - const { offsetX, offsetY } = this.editor.refLine.updateRefLine(record); + const targetPoints = RefLine.getGraphicsTargetPoints(record); + const offset = this.editor.refLine.getGraphicsSnapOffset(targetPoints); const canvasGraphics = this.editor.doc.getCanvas(); const newParent = @@ -155,8 +157,8 @@ export class SelectMoveTool implements IBaseTool { const newWorldTf = cloneDeep( this.originWorldTfMap.get(graphics.attrs.id)!, ); - newWorldTf[4] += dx + offsetX; - newWorldTf[5] += dy + offsetY; + newWorldTf[4] += dx + (offset?.x ?? 0); + newWorldTf[5] += dy + (offset?.y ?? 0); // change parent if (this.prevParent !== newParent) {