@flowgram.ai/free-snap-plugin 0.4.12 → 0.4.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/dist/esm/index.js
CHANGED
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/create-plugin.ts","../../src/service.ts","../../src/constant.ts","../../src/utils.ts","../../src/layer.tsx"],"sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { definePluginCreator } from '@flowgram.ai/core';\n\nimport {\n FreeSnapPluginOptions,\n WorkflowSnapLayerOptions,\n WorkflowSnapServiceOptions,\n} from './type';\nimport { WorkflowSnapService } from './service';\nimport { WorkflowSnapLayer } from './layer';\nimport { SnapDefaultOptions } from './constant';\n\nexport const createFreeSnapPlugin = definePluginCreator<FreeSnapPluginOptions>({\n onBind({ bind }) {\n bind(WorkflowSnapService).toSelf().inSingletonScope();\n },\n onInit(ctx, opts) {\n const options: WorkflowSnapServiceOptions & WorkflowSnapLayerOptions = {\n ...SnapDefaultOptions,\n ...opts,\n };\n ctx.playground.registerLayer(WorkflowSnapLayer, options);\n const snapService = ctx.get<WorkflowSnapService>(WorkflowSnapService);\n snapService.init(options);\n },\n onDispose(ctx) {\n const snapService = ctx.get<WorkflowSnapService>(WorkflowSnapService);\n snapService.dispose();\n },\n});\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { inject, injectable } from 'inversify';\nimport { Disposable, Emitter, Rectangle } from '@flowgram.ai/utils';\nimport { IPoint } from '@flowgram.ai/utils';\nimport { WorkflowNodeEntity, WorkflowDocument } from '@flowgram.ai/free-layout-core';\nimport { WorkflowDragService } from '@flowgram.ai/free-layout-core';\nimport { FlowNodeTransformData } from '@flowgram.ai/document';\nimport { FlowNodeBaseType } from '@flowgram.ai/document';\nimport { EntityManager, PlaygroundConfigEntity, TransformData } from '@flowgram.ai/core';\n\nimport { isEqual, isGreaterThan, isLessThan, isLessThanOrEqual, isNumber } from './utils';\nimport type {\n SnapEvent,\n SnapHorizontalLine,\n SnapLines,\n SnapMidHorizontalLine,\n SnapMidVerticalLine,\n SnapVerticalLine,\n WorkflowSnapServiceOptions,\n AlignRects,\n AlignRect,\n AlignSpacing,\n SnapNodeRect,\n SnapEdgeLines,\n} from './type';\nimport { SnapDefaultOptions } from './constant';\n\n@injectable()\nexport class WorkflowSnapService {\n @inject(WorkflowDocument) private readonly document: WorkflowDocument;\n\n @inject(EntityManager) private readonly entityManager: EntityManager;\n\n @inject(WorkflowDragService)\n private readonly dragService: WorkflowDragService;\n\n @inject(PlaygroundConfigEntity)\n private readonly playgroundConfig: PlaygroundConfigEntity;\n\n private disposers: Disposable[] = [];\n\n private options: WorkflowSnapServiceOptions;\n\n private snapEmitter = new Emitter<SnapEvent>();\n\n public readonly onSnap = this.snapEmitter.event;\n\n private _disabled = false;\n\n public init(params: Partial<WorkflowSnapServiceOptions> = {}): void {\n this.options = {\n ...SnapDefaultOptions,\n ...params,\n };\n this.mountListener();\n }\n\n public dispose(): void {\n this.disposers.forEach((disposer) => disposer.dispose());\n }\n\n public get disabled(): boolean {\n return this._disabled;\n }\n\n public disable(): void {\n if (this._disabled) {\n return;\n }\n this._disabled = true;\n this.clear();\n }\n\n public enable(): void {\n if (!this._disabled) {\n return;\n }\n this._disabled = false;\n this.clear();\n }\n\n private mountListener(): void {\n const dragAdjusterDisposer = this.dragService.registerPosAdjuster((params) => {\n const { selectedNodes: targetNodes, position } = params;\n const isMultiSnapping = this.options.enableMultiSnapping ? false : targetNodes.length !== 1;\n if (this._disabled || !this.options.enableEdgeSnapping || isMultiSnapping) {\n return {\n x: 0,\n y: 0,\n };\n }\n return this.snapping({\n targetNodes,\n position,\n });\n });\n const dragEndDisposer = this.dragService.onNodesDrag((event) => {\n if (event.type !== 'onDragEnd' || this._disabled) {\n return;\n }\n if (this.options.enableGridSnapping) {\n this.gridSnapping({\n targetNodes: event.nodes,\n gridSize: this.options.gridSize,\n });\n }\n if (this.options.enableEdgeSnapping) {\n this.clear();\n }\n });\n this.disposers.push(dragAdjusterDisposer, dragEndDisposer);\n }\n\n private snapping(params: { targetNodes: WorkflowNodeEntity[]; position: IPoint }): IPoint {\n const { targetNodes, position } = params;\n\n const targetBounds = this.getBounds(targetNodes);\n\n const targetRect = new Rectangle(\n position.x,\n position.y,\n targetBounds.width,\n targetBounds.height\n );\n\n const snapNodeRects = this.getSnapNodeRects({\n targetNodes,\n targetRect,\n });\n\n const { alignOffset, alignRects, alignSpacing } = this.calcAlignOffset({\n targetRect,\n alignThreshold: this.options.edgeThreshold,\n snapNodeRects,\n });\n\n const { snapOffset, snapEdgeLines } = this.calcSnapOffset({\n targetRect,\n edgeThreshold: this.options.edgeThreshold,\n snapNodeRects,\n });\n\n const offset: IPoint = {\n x: snapOffset.x || alignOffset.x,\n y: snapOffset.y || alignOffset.y,\n };\n\n const snapRect = new Rectangle(\n position.x + offset.x,\n position.y + offset.y,\n targetRect.width,\n targetRect.height\n );\n\n this.snapEmitter.fire({\n snapRect,\n snapEdgeLines,\n alignRects,\n alignSpacing,\n });\n\n return offset;\n }\n\n private calcSnapOffset(params: {\n snapNodeRects: SnapNodeRect[];\n targetRect: Rectangle;\n edgeThreshold: number;\n }): {\n snapOffset: IPoint;\n snapEdgeLines: SnapEdgeLines;\n } {\n const { snapNodeRects, edgeThreshold, targetRect } = params;\n\n const snapLines = this.getSnapLines({\n snapNodeRects,\n });\n\n // 找到最近的线条\n const topYClosestLine = snapLines.horizontal.find((line) =>\n isLessThanOrEqual(Math.abs(line.y - targetRect.top), edgeThreshold)\n );\n const bottomYClosestLine = snapLines.horizontal.find((line) =>\n isLessThanOrEqual(Math.abs(line.y - targetRect.bottom), edgeThreshold)\n );\n const leftXClosestLine = snapLines.vertical.find((line) =>\n isLessThanOrEqual(Math.abs(line.x - targetRect.left), edgeThreshold)\n );\n const rightXClosestLine = snapLines.vertical.find((line) =>\n isLessThanOrEqual(Math.abs(line.x - targetRect.right), edgeThreshold)\n );\n const midYClosestLine = snapLines.midHorizontal.find((line) =>\n isLessThanOrEqual(Math.abs(line.y - targetRect.center.y), edgeThreshold)\n );\n const midXClosestLine = snapLines.midVertical.find((line) =>\n isLessThanOrEqual(Math.abs(line.x - targetRect.center.x), edgeThreshold)\n );\n\n // 计算最近坐标\n const topYClosest = topYClosestLine?.y;\n const bottomYClosest = isNumber(bottomYClosestLine?.y)\n ? bottomYClosestLine!.y - targetRect.height\n : undefined;\n const leftXClosest = leftXClosestLine?.x;\n const rightXClosest = isNumber(rightXClosestLine?.x)\n ? rightXClosestLine!.x - targetRect.width\n : undefined;\n const midYClosest = isNumber(midYClosestLine?.y)\n ? midYClosestLine!.y - targetRect.height / 2\n : undefined;\n const midXClosest = isNumber(midXClosestLine?.x)\n ? midXClosestLine!.x - targetRect.width / 2\n : undefined;\n\n // 吸附后坐标,按优先级取值\n const snappingPosition = {\n x: midXClosest ?? leftXClosest ?? rightXClosest ?? targetRect.x,\n y: midYClosest ?? topYClosest ?? bottomYClosest ?? targetRect.y,\n };\n\n // 吸附修正偏移量\n const snapOffset: IPoint = {\n x: snappingPosition.x - targetRect.x,\n y: snappingPosition.y - targetRect.y,\n };\n\n // 生效的吸附线条\n const snapEdgeLines: SnapEdgeLines = {\n top: isEqual(topYClosest, snappingPosition.y) ? topYClosestLine : undefined,\n bottom: isEqual(bottomYClosest, snappingPosition.y) ? bottomYClosestLine : undefined,\n left: isEqual(leftXClosest, snappingPosition.x) ? leftXClosestLine : undefined,\n right: isEqual(rightXClosest, snappingPosition.x) ? rightXClosestLine : undefined,\n midVertical: isEqual(midXClosest, snappingPosition.x) ? midXClosestLine : undefined,\n midHorizontal: isEqual(midYClosest, snappingPosition.y) ? midYClosestLine : undefined,\n };\n\n return { snapOffset, snapEdgeLines };\n }\n\n private gridSnapping(params: { gridSize: number; targetNodes: WorkflowNodeEntity[] }): void {\n const { gridSize, targetNodes } = params;\n const rect = this.getBounds(targetNodes);\n const snap = (value: number) => Math.round(value / gridSize) * gridSize;\n const snappedPosition: IPoint = {\n x: snap(rect.x),\n y: snap(rect.y),\n };\n const offset: IPoint = {\n x: snappedPosition.x - rect.x,\n y: snappedPosition.y - rect.y,\n };\n targetNodes.forEach((node) =>\n this.updateNodePositionWithOffset({\n node,\n offset,\n })\n );\n }\n\n private clear() {\n this.snapEmitter.fire({\n snapEdgeLines: {},\n snapRect: Rectangle.EMPTY,\n alignRects: {\n top: [],\n bottom: [],\n left: [],\n right: [],\n },\n alignSpacing: {},\n });\n }\n\n private getSnapLines(params: { snapNodeRects: SnapNodeRect[] }): SnapLines {\n const { snapNodeRects } = params;\n const horizontalLines: SnapHorizontalLine[] = [];\n const verticalLines: SnapVerticalLine[] = [];\n const midHorizontalLines: SnapMidHorizontalLine[] = [];\n const midVerticalLines: SnapMidVerticalLine[] = [];\n\n snapNodeRects.forEach((snapNodeRect) => {\n const nodeBounds = snapNodeRect.rect;\n const nodeCenter = nodeBounds.center;\n // 边缘横线\n const top: SnapHorizontalLine = {\n y: nodeBounds.top,\n sourceNodeId: snapNodeRect.id,\n };\n const bottom: SnapHorizontalLine = {\n y: nodeBounds.bottom,\n sourceNodeId: snapNodeRect.id,\n };\n // 边缘竖线\n const left: SnapVerticalLine = {\n x: nodeBounds.left,\n sourceNodeId: snapNodeRect.id,\n };\n const right: SnapVerticalLine = {\n x: nodeBounds.right,\n sourceNodeId: snapNodeRect.id,\n };\n // 中间横线\n const midHorizontal: SnapMidHorizontalLine = {\n y: nodeCenter.y,\n sourceNodeId: snapNodeRect.id,\n };\n // 中间竖线\n const midVertical: SnapMidVerticalLine = {\n x: nodeCenter.x,\n sourceNodeId: snapNodeRect.id,\n };\n horizontalLines.push(top, bottom);\n verticalLines.push(left, right);\n midHorizontalLines.push(midHorizontal);\n midVerticalLines.push(midVertical);\n });\n\n return {\n horizontal: horizontalLines,\n vertical: verticalLines,\n midHorizontal: midHorizontalLines,\n midVertical: midVerticalLines,\n };\n }\n\n private getAvailableNodes(params: {\n targetNodes: WorkflowNodeEntity[];\n targetRect: Rectangle;\n }): WorkflowNodeEntity[] {\n const { targetNodes, targetRect } = params;\n\n const targetCenter = targetRect.center;\n const targetContainerId = targetNodes[0].parent?.id ?? this.document.root.id;\n\n const disabledNodeIds = targetNodes.map((n) => n.id);\n disabledNodeIds.push(FlowNodeBaseType.ROOT);\n const availableNodes = this.nodes\n .filter((n) => n.parent?.id === targetContainerId)\n .filter((n) => !disabledNodeIds.includes(n.id))\n .sort((nodeA, nodeB) => {\n const nodeCenterA = nodeA.getData(FlowNodeTransformData)!.bounds.center;\n const nodeCenterB = nodeB.getData(FlowNodeTransformData)!.bounds.center;\n // 距离越近优先级越高\n const distanceA =\n Math.abs(nodeCenterA.x - targetCenter.x) + Math.abs(nodeCenterA.y - targetCenter.y);\n const distanceB =\n Math.abs(nodeCenterB.x - targetCenter.x) + Math.abs(nodeCenterB.y - targetCenter.y);\n return distanceA - distanceB;\n });\n return availableNodes;\n }\n\n private viewRect(): Rectangle {\n const { width, height, scrollX, scrollY, zoom } = this.playgroundConfig.config;\n return new Rectangle(scrollX / zoom, scrollY / zoom, width / zoom, height / zoom);\n }\n\n private getSnapNodeRects(params: {\n targetNodes: WorkflowNodeEntity[];\n targetRect: Rectangle;\n }): SnapNodeRect[] {\n const availableNodes = this.getAvailableNodes(params);\n const viewRect = this.viewRect();\n return availableNodes\n .map((node) => {\n const snapNodeRect: SnapNodeRect = {\n id: node.id,\n rect: node.getData(FlowNodeTransformData).bounds,\n entity: node,\n };\n if (\n this.options.enableOnlyViewportSnapping &&\n node.parent?.flowNodeType === FlowNodeBaseType.ROOT &&\n !Rectangle.intersects(viewRect, snapNodeRect.rect)\n ) {\n // 最外层节点仅包含当前可见节点\n return;\n }\n return snapNodeRect;\n })\n .filter(Boolean) as SnapNodeRect[];\n }\n\n private get nodes(): WorkflowNodeEntity[] {\n return this.entityManager.getEntities<WorkflowNodeEntity>(WorkflowNodeEntity);\n }\n\n private getBounds(nodes: WorkflowNodeEntity[]): Rectangle {\n if (nodes.length === 0) {\n return Rectangle.EMPTY;\n }\n return Rectangle.enlarge(nodes.map((n) => n.getData(FlowNodeTransformData)!.bounds));\n }\n\n private updateNodePositionWithOffset(params: { node: WorkflowNodeEntity; offset: IPoint }): void {\n const { node, offset } = params;\n const transform = node.getData(TransformData);\n const positionWithOffset: IPoint = {\n x: transform.position.x + offset.x,\n y: transform.position.y + offset.y,\n };\n transform.update({\n position: positionWithOffset,\n });\n this.document.layout.updateAffectedTransform(node);\n }\n\n private calcAlignOffset(params: {\n snapNodeRects: SnapNodeRect[];\n targetRect: Rectangle;\n alignThreshold: number;\n }): {\n alignOffset: IPoint;\n alignRects: AlignRects;\n alignSpacing: AlignSpacing;\n } {\n const { snapNodeRects, targetRect, alignThreshold } = params;\n\n const alignRects = this.getAlignRects({\n targetRect,\n snapNodeRects,\n });\n\n const alignSpacing = this.calcAlignSpacing({\n targetRect,\n alignRects,\n });\n\n let topY: number | undefined;\n let bottomY: number | undefined;\n let leftX: number | undefined;\n let rightX: number | undefined;\n let midY: number | undefined;\n let midX: number | undefined;\n\n if (alignSpacing.top) {\n const topAlignY = alignRects.top[0].rect.bottom + alignSpacing.top;\n const isAlignTop = isLessThanOrEqual(Math.abs(targetRect.top - topAlignY), alignThreshold);\n if (isAlignTop) {\n // 生效\n topY = topAlignY;\n } else {\n // 失效\n alignSpacing.top = undefined;\n }\n }\n if (alignSpacing.bottom) {\n const bottomAlignY = alignRects.bottom[0].rect.top - alignSpacing.bottom;\n const isAlignBottom = isLessThan(Math.abs(targetRect.bottom - bottomAlignY), alignThreshold);\n if (isAlignBottom) {\n bottomY = bottomAlignY - targetRect.height;\n } else {\n alignSpacing.bottom = undefined;\n }\n }\n if (alignSpacing.left) {\n const leftAlignX = alignRects.left[0].rect.right + alignSpacing.left;\n const isAlignLeft = isLessThanOrEqual(Math.abs(targetRect.left - leftAlignX), alignThreshold);\n if (isAlignLeft) {\n leftX = leftAlignX;\n } else {\n alignSpacing.left = undefined;\n }\n }\n if (alignSpacing.right) {\n const rightAlignX = alignRects.right[0].rect.left - alignSpacing.right;\n const isAlignRight = isLessThanOrEqual(\n Math.abs(targetRect.right - rightAlignX),\n alignThreshold\n );\n if (isAlignRight) {\n rightX = rightAlignX - targetRect.width;\n } else {\n alignSpacing.right = undefined;\n }\n }\n if (alignSpacing.midHorizontal) {\n const leftAlignX = alignRects.left[0].rect.right + alignSpacing.midHorizontal;\n const isAlignMidHorizontal = isLessThanOrEqual(\n Math.abs(targetRect.left - leftAlignX),\n alignThreshold\n );\n if (isAlignMidHorizontal) {\n midX = leftAlignX;\n } else {\n alignSpacing.midHorizontal = undefined;\n }\n }\n if (alignSpacing.midVertical) {\n const topAlignY = alignRects.top[0].rect.bottom + alignSpacing.midVertical;\n const isAlignMidVertical = isLessThanOrEqual(\n Math.abs(targetRect.top - topAlignY),\n alignThreshold\n );\n if (isAlignMidVertical) {\n midY = topAlignY;\n } else {\n alignSpacing.midVertical = undefined;\n }\n }\n\n const alignPosition: IPoint = {\n x: midX ?? leftX ?? rightX ?? targetRect.x,\n y: midY ?? topY ?? bottomY ?? targetRect.y,\n };\n\n const alignOffset: IPoint = {\n x: alignPosition.x - targetRect.x,\n y: alignPosition.y - targetRect.y,\n };\n\n return { alignOffset, alignRects, alignSpacing };\n }\n\n private calcAlignSpacing(params: {\n targetRect: Rectangle;\n alignRects: AlignRects;\n }): AlignSpacing {\n const { targetRect, alignRects } = params;\n\n const topSpacing = this.getDirectionAlignSpacing({\n rects: alignRects.top,\n isHorizontal: false,\n });\n const bottomSpacing = this.getDirectionAlignSpacing({\n rects: alignRects.bottom,\n isHorizontal: false,\n });\n const leftSpacing = this.getDirectionAlignSpacing({\n rects: alignRects.left,\n isHorizontal: true,\n });\n const rightSpacing = this.getDirectionAlignSpacing({\n rects: alignRects.right,\n isHorizontal: true,\n });\n const midHorizontalSpacing = this.getMidAlignSpacing({\n rectA: alignRects.left[0]?.rect,\n rectB: alignRects.right[0]?.rect,\n targetRect,\n isHorizontal: true,\n });\n const midVerticalSpacing = this.getMidAlignSpacing({\n rectA: alignRects.top[0]?.rect,\n rectB: alignRects.bottom[0]?.rect,\n targetRect,\n isHorizontal: false,\n });\n return {\n top: topSpacing,\n bottom: bottomSpacing,\n left: leftSpacing,\n right: rightSpacing,\n midHorizontal: midHorizontalSpacing,\n midVertical: midVerticalSpacing,\n };\n }\n\n private getAlignRects(params: {\n targetRect: Rectangle;\n snapNodeRects: SnapNodeRect[];\n }): AlignRects {\n const { targetRect, snapNodeRects } = params;\n\n const topVerticalRects: AlignRect[] = [];\n const bottomVerticalRects: AlignRect[] = [];\n const leftHorizontalRects: AlignRect[] = [];\n const rightHorizontalRects: AlignRect[] = [];\n\n snapNodeRects.forEach((snapNodeRect) => {\n const nodeRect = snapNodeRect.rect;\n const { isVerticalIntersection, isHorizontalIntersection, isIntersection } =\n this.intersection(nodeRect, targetRect);\n if (isIntersection) {\n // 忽略重叠的节点\n return;\n } else if (isVerticalIntersection) {\n // 垂直重合\n if (isGreaterThan(nodeRect.center.y, targetRect.center.y)) {\n // 下方\n bottomVerticalRects.push({\n rect: nodeRect,\n sourceNodeId: snapNodeRect.id,\n });\n } else {\n // 上方\n topVerticalRects.push({\n rect: nodeRect,\n sourceNodeId: snapNodeRect.id,\n });\n }\n } else if (isHorizontalIntersection) {\n // 水平重合\n if (isGreaterThan(nodeRect.center.x, targetRect.center.x)) {\n // 右方\n rightHorizontalRects.push({\n rect: nodeRect,\n sourceNodeId: snapNodeRect.id,\n });\n } else {\n // 左方\n leftHorizontalRects.push({\n rect: nodeRect,\n sourceNodeId: snapNodeRect.id,\n });\n }\n }\n });\n\n return {\n top: topVerticalRects,\n bottom: bottomVerticalRects,\n left: leftHorizontalRects,\n right: rightHorizontalRects,\n };\n }\n\n private getMidAlignSpacing(params: {\n rectA?: Rectangle;\n rectB?: Rectangle;\n targetRect: Rectangle;\n isHorizontal: boolean;\n }): number | undefined {\n const { rectA, rectB, targetRect, isHorizontal } = params;\n if (!rectA || !rectB) {\n return;\n }\n const { isVerticalIntersection, isHorizontalIntersection, isIntersection } = this.intersection(\n rectA,\n rectB\n );\n if (isIntersection) {\n return;\n }\n if (isHorizontal && isHorizontalIntersection && !isVerticalIntersection) {\n const betweenSpacing = Math.min(\n Math.abs(rectA.left - rectB.right),\n Math.abs(rectA.right - rectB.left)\n );\n return (betweenSpacing - targetRect.width) / 2;\n } else if (!isHorizontal && isVerticalIntersection && !isHorizontalIntersection) {\n const betweenSpacing = Math.min(\n Math.abs(rectA.top - rectB.bottom),\n Math.abs(rectA.bottom - rectB.top)\n );\n return (betweenSpacing - targetRect.height) / 2;\n }\n }\n\n private getDirectionAlignSpacing(params: {\n rects: AlignRect[];\n isHorizontal: boolean;\n }): number | undefined {\n const { rects, isHorizontal } = params;\n if (rects.length < 2) {\n // 非法情况\n return;\n }\n const rectA = rects[0].rect;\n const rectB = rects[1].rect;\n\n const { isVerticalIntersection, isHorizontalIntersection, isIntersection } = this.intersection(\n rectA,\n rectB\n );\n\n if (isIntersection) {\n // 非法情况:重叠\n return;\n }\n if (isHorizontal && isHorizontalIntersection && !isVerticalIntersection) {\n return Math.min(Math.abs(rectA.left - rectB.right), Math.abs(rectA.right - rectB.left));\n } else if (!isHorizontal && isVerticalIntersection && !isHorizontalIntersection) {\n return Math.min(Math.abs(rectA.top - rectB.bottom), Math.abs(rectA.bottom - rectB.top));\n }\n return;\n }\n\n private intersection(\n rectA: Rectangle,\n rectB: Rectangle\n ): {\n isHorizontalIntersection: boolean;\n isVerticalIntersection: boolean;\n isIntersection: boolean;\n } {\n const isVerticalIntersection =\n isLessThan(rectA.left, rectB.right) && isGreaterThan(rectA.right, rectB.left);\n const isHorizontalIntersection =\n isLessThan(rectA.top, rectB.bottom) && isGreaterThan(rectA.bottom, rectB.top);\n const isIntersection = isHorizontalIntersection && isVerticalIntersection;\n\n return {\n isHorizontalIntersection,\n isVerticalIntersection,\n isIntersection,\n };\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport type { WorkflowSnapLayerOptions, WorkflowSnapServiceOptions } from './type';\n\nexport const SnapDefaultOptions: WorkflowSnapServiceOptions & WorkflowSnapLayerOptions = {\n enableEdgeSnapping: true,\n edgeThreshold: 7,\n enableGridSnapping: false,\n gridSize: 20,\n enableMultiSnapping: false,\n enableOnlyViewportSnapping: true,\n edgeColor: '#4E40E5',\n alignColor: '#4E40E5',\n edgeLineWidth: 2,\n alignLineWidth: 2,\n alignCrossWidth: 16,\n};\n\nexport const Epsilon = 0.00001;\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { Epsilon } from './constant';\n\n/** 检查浮点数 a 是否等于 b */\nexport const isEqual = (a: number | undefined, b: number | undefined): boolean => {\n if (a === undefined || b === undefined) {\n return false;\n }\n // 检查 a 和 b 的差的绝对值是否小于 Epsilon\n return Math.abs(a - b) < Epsilon;\n};\n\n/** 检查浮点数 a 是否小于 b */\nexport const isLessThan = (a: number | undefined, b: number | undefined): boolean => {\n if (a === undefined || b === undefined) {\n return false;\n }\n // 检查 a 是否显著小于 b\n return b - a > Epsilon;\n};\n\n/** 检查浮点数 a 是否大于 b */\nexport const isGreaterThan = (a: number | undefined, b: number | undefined): boolean => {\n if (a === undefined || b === undefined) {\n return false;\n }\n return a - b > Epsilon;\n};\n\n/** 检查浮点数 a 是否小于等于 b */\nexport const isLessThanOrEqual = (a: number | undefined, b: number | undefined): boolean =>\n isEqual(a, b) || isLessThan(a, b);\n\n/** 检查浮点数 a 是否大于等于 b */\nexport const isGreaterThanOrEqual = (a: number | undefined, b: number | undefined): boolean =>\n isEqual(a, b) || isGreaterThan(a, b);\n\n/** 检查值是否是数字类型 */\nexport const isNumber = (value: unknown): value is number =>\n typeof value === 'number' && !isNaN(value);\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React from 'react';\n\nimport { inject, injectable } from 'inversify';\nimport { domUtils } from '@flowgram.ai/utils';\nimport { Rectangle } from '@flowgram.ai/utils';\nimport { WorkflowDocument } from '@flowgram.ai/free-layout-core';\nimport { FlowNodeTransformData } from '@flowgram.ai/document';\nimport { Layer } from '@flowgram.ai/core';\n\nimport { isEqual, isGreaterThan, isNumber } from './utils';\nimport { AlignRect, SnapEvent, WorkflowSnapLayerOptions } from './type';\nimport { WorkflowSnapService } from './service';\n\ninterface SnapRenderLine {\n className: string;\n sourceNode: string;\n top: number;\n left: number;\n width: number;\n height: number;\n dashed?: boolean;\n}\n\n@injectable()\nexport class WorkflowSnapLayer extends Layer<WorkflowSnapLayerOptions> {\n public static type = 'WorkflowSnapLayer';\n\n @inject(WorkflowDocument) private readonly document: WorkflowDocument;\n\n @inject(WorkflowSnapService) private readonly service: WorkflowSnapService;\n\n public readonly node = domUtils.createDivWithClass(\n 'gedit-playground-layer gedit-flow-snap-layer'\n );\n\n private edgeLines: SnapRenderLine[] = [];\n\n private alignLines: SnapRenderLine[] = [];\n\n public onReady(): void {\n this.node.style.zIndex = '9999';\n this.toDispose.pushAll([\n this.service.onSnap((event: SnapEvent) => {\n this.edgeLines = this.calcEdgeLines(event);\n this.alignLines = this.calcAlignLines(event);\n this.render();\n }),\n ]);\n }\n\n public render(): JSX.Element {\n return (\n <>\n {this.alignLines.length > 0 && (\n <div className=\"workflow-snap-align-lines\">{this.renderAlignLines()}</div>\n )}\n {this.edgeLines.length > 0 && (\n <div className=\"workflow-snap-edge-lines\">{this.renderEdgeLines()}</div>\n )}\n </>\n );\n }\n\n public onZoom(scale: number): void {\n this.node.style.transform = `scale(${scale})`;\n }\n\n private renderEdgeLines(): JSX.Element[] {\n return this.edgeLines.map((renderLine: SnapRenderLine) => {\n const { className, sourceNode, top, left, width, height, dashed } = renderLine;\n const id = `${className}-${sourceNode}-${top}-${left}-${width}-${height}`;\n const isHorizontal = width < height;\n const border = `${this.options.edgeLineWidth}px ${dashed ? 'dashed' : 'solid'} ${\n this.options.edgeColor\n }`;\n return (\n <div\n className={`workflow-snap-edge-line ${className}`}\n data-testid=\"sdk.workflow.canvas.snap.edgeLine\"\n data-snap-line-id={id}\n data-snap-line-source-node={sourceNode}\n key={id}\n style={{\n top,\n left,\n width,\n height,\n position: 'absolute',\n borderLeft: isHorizontal ? border : 'none',\n borderTop: !isHorizontal ? border : 'none',\n }}\n />\n );\n });\n }\n\n private renderAlignLines(): JSX.Element[] {\n return this.alignLines.map((renderLine: SnapRenderLine) => {\n const id = `${renderLine.className}-${renderLine.sourceNode}-${renderLine.top}-${renderLine.left}-${renderLine.width}-${renderLine.height}`;\n const isHorizontal = isGreaterThan(renderLine.width, renderLine.height);\n const alignLineWidth = this.options.alignLineWidth; // 整体线条粗细\n const alignCrossWidth = this.options.alignCrossWidth; // 工字形横线的长度\n\n // 调整渲染位置以保持居中\n const adjustedTop = isHorizontal ? renderLine.top - alignLineWidth / 2 : renderLine.top;\n const adjustedLeft = isHorizontal ? renderLine.left : renderLine.left - alignLineWidth / 2;\n\n return (\n <div\n className={`workflow-snap-align-line ${renderLine.className}`}\n data-testid=\"sdk.workflow.canvas.snap.alignLine\"\n data-snap-line-id={id}\n data-snap-line-source-node={renderLine.sourceNode}\n key={id}\n style={{\n position: 'absolute',\n }}\n >\n {/* 主线 */}\n <div\n style={{\n position: 'absolute',\n top: adjustedTop,\n left: adjustedLeft,\n width: isHorizontal ? renderLine.width : alignLineWidth,\n height: isHorizontal ? alignLineWidth : renderLine.height,\n backgroundColor: this.options.alignColor,\n }}\n />\n {/* 左端或上端横线 */}\n <div\n style={{\n position: 'absolute',\n top: isHorizontal\n ? adjustedTop - (alignCrossWidth - alignLineWidth) / 2\n : adjustedTop,\n left: isHorizontal\n ? adjustedLeft\n : adjustedLeft - (alignCrossWidth - alignLineWidth) / 2,\n width: isHorizontal ? alignLineWidth : alignCrossWidth,\n height: isHorizontal ? alignCrossWidth : alignLineWidth,\n backgroundColor: this.options.alignColor,\n }}\n />\n {/* 右端或下端横线 */}\n <div\n style={{\n position: 'absolute',\n top: isHorizontal\n ? adjustedTop - (alignCrossWidth - alignLineWidth) / 2\n : adjustedTop + renderLine.height - alignLineWidth,\n left: isHorizontal\n ? adjustedLeft + renderLine.width - alignLineWidth\n : adjustedLeft - (alignCrossWidth - alignLineWidth) / 2,\n width: isHorizontal ? alignLineWidth : alignCrossWidth,\n height: isHorizontal ? alignCrossWidth : alignLineWidth,\n backgroundColor: this.options.alignColor,\n }}\n />\n </div>\n );\n });\n }\n\n private calcEdgeLines(event: SnapEvent): SnapRenderLine[] {\n const { alignRects, snapRect, snapEdgeLines } = event;\n const edgeLines: SnapRenderLine[] = [];\n\n const topFullAlign = this.directionFullAlign({\n alignRects: alignRects.top,\n targetRect: snapRect,\n isVertical: true,\n });\n const bottomFullAlign = this.directionFullAlign({\n alignRects: alignRects.bottom,\n targetRect: snapRect,\n isVertical: true,\n });\n const leftFullAlign = this.directionFullAlign({\n alignRects: alignRects.left,\n targetRect: snapRect,\n isVertical: false,\n });\n const rightFullAlign = this.directionFullAlign({\n alignRects: alignRects.right,\n targetRect: snapRect,\n isVertical: false,\n });\n\n // 处理顶部对齐\n if (topFullAlign) {\n const top = topFullAlign.rect.top;\n const height = bottomFullAlign\n ? snapRect.bottom - snapRect.height / 2 - top\n : snapRect.bottom - top;\n const width = this.options.edgeLineWidth;\n const lineData = {\n top,\n width,\n height,\n };\n edgeLines.push({\n className: 'edge-full-top-left',\n sourceNode: topFullAlign.sourceNodeId,\n left: snapRect.left,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-top-right',\n sourceNode: topFullAlign.sourceNodeId,\n left: snapRect.right,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-top-mid',\n sourceNode: topFullAlign.sourceNodeId,\n left: snapRect.left + snapRect.width / 2,\n dashed: true,\n ...lineData,\n });\n }\n\n // 处理底部对齐\n if (bottomFullAlign) {\n const top = topFullAlign ? snapRect.top + snapRect.height / 2 : snapRect.top;\n const height = bottomFullAlign.rect.bottom - top;\n const width = this.options.edgeLineWidth;\n const lineData = {\n top,\n width,\n height,\n };\n edgeLines.push({\n className: 'edge-full-bottom-left',\n sourceNode: bottomFullAlign.sourceNodeId,\n left: snapRect.left,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-bottom-right',\n sourceNode: bottomFullAlign.sourceNodeId,\n left: snapRect.right,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-bottom-mid',\n sourceNode: bottomFullAlign.sourceNodeId,\n left: snapRect.left + snapRect.width / 2,\n dashed: true,\n ...lineData,\n });\n }\n\n // 处理左侧对齐\n if (leftFullAlign) {\n const left = leftFullAlign.rect.left;\n const width = rightFullAlign\n ? snapRect.right - snapRect.width / 2 - left\n : snapRect.right - left;\n const height = this.options.edgeLineWidth;\n const lineData = {\n left,\n width,\n height,\n };\n edgeLines.push({\n className: 'edge-full-left-top',\n sourceNode: leftFullAlign.sourceNodeId,\n top: snapRect.top,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-left-bottom',\n sourceNode: leftFullAlign.sourceNodeId,\n top: snapRect.bottom,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-left-mid',\n sourceNode: leftFullAlign.sourceNodeId,\n top: snapRect.top + snapRect.height / 2,\n dashed: true,\n ...lineData,\n });\n }\n\n // 处理右侧对齐\n if (rightFullAlign) {\n const left = leftFullAlign ? snapRect.left + snapRect.width / 2 : snapRect.left;\n const width = rightFullAlign.rect.right - left;\n const height = this.options.edgeLineWidth;\n const lineData = {\n left,\n width,\n height,\n };\n edgeLines.push({\n className: 'edge-full-right-top',\n sourceNode: rightFullAlign.sourceNodeId,\n top: snapRect.top,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-right-bottom',\n sourceNode: rightFullAlign.sourceNodeId,\n top: snapRect.bottom,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-right-mid',\n sourceNode: rightFullAlign.sourceNodeId,\n top: snapRect.top + snapRect.height / 2,\n dashed: true,\n ...lineData,\n });\n }\n\n const snappedEdgeLines = Object.entries(snapEdgeLines)\n .map(([direction, snapLine]) => {\n if (!snapLine) {\n return;\n }\n const sourceNode = this.document.getNode(snapLine.sourceNodeId);\n if (!sourceNode) {\n return;\n }\n const nodeRect = sourceNode.getData(FlowNodeTransformData).bounds;\n if (isNumber(snapLine.x)) {\n // 垂直\n const top = Math.min(nodeRect.top, snapRect.top);\n const bottom = Math.max(nodeRect.bottom, snapRect.bottom);\n const height = bottom - top;\n const left = snapLine.x;\n const width = this.options.edgeLineWidth;\n const isMidX = direction === 'midVertical';\n const lineData: SnapRenderLine = {\n className: `edge-snapped-${direction}`,\n sourceNode: snapLine.sourceNodeId,\n top,\n left,\n width,\n height,\n dashed: isMidX,\n };\n const onTop = top === nodeRect.top;\n if (onTop && topFullAlign) {\n return;\n }\n if (!onTop && bottomFullAlign) {\n return;\n }\n return lineData;\n } else if (isNumber(snapLine.y)) {\n // 水平\n const left = Math.min(nodeRect.left, snapRect.left);\n const right = Math.max(nodeRect.right, snapRect.right);\n const width = right - left;\n const top = snapLine.y;\n const height = this.options.edgeLineWidth;\n const isMidY = direction === 'midHorizontal';\n const lineData: SnapRenderLine = {\n className: `edge-snapped-${direction}`,\n sourceNode: snapLine.sourceNodeId,\n top,\n left,\n width,\n height,\n dashed: isMidY,\n };\n const onLeft = left === nodeRect.left;\n if (onLeft && leftFullAlign) {\n return;\n }\n if (!onLeft && rightFullAlign) {\n return;\n }\n return lineData;\n }\n })\n .filter(Boolean) as SnapRenderLine[];\n\n edgeLines.push(...snappedEdgeLines);\n\n return edgeLines;\n }\n\n private directionFullAlign(params: {\n alignRects: AlignRect[];\n targetRect: Rectangle;\n isVertical: boolean;\n }): AlignRect | undefined {\n const { alignRects, targetRect, isVertical } = params;\n let fullAlignIndex = -1;\n for (let i = 0; i < alignRects.length; i++) {\n const alignRect = alignRects[i];\n const prevRect = alignRects[i - 1]?.rect ?? targetRect;\n const isFullAlign = this.rectFullAlign(alignRect.rect, prevRect, isVertical);\n if (!isFullAlign) {\n // 未对齐则中断\n break; // 用 for 循环 + break 反而比 Array.findIndex 实现可读性更好\n }\n fullAlignIndex = i;\n }\n const fullAlignRect = alignRects[fullAlignIndex];\n return fullAlignRect;\n }\n\n private rectFullAlign(rectA: Rectangle, rectB: Rectangle, isVertical: boolean): boolean {\n if (isVertical) {\n return isEqual(rectA.left, rectB.left) && isEqual(rectA.right, rectB.right);\n } else {\n return isEqual(rectA.top, rectB.top) && isEqual(rectA.bottom, rectB.bottom);\n }\n }\n\n private calcAlignLines(event: SnapEvent): SnapRenderLine[] {\n const { alignRects, alignSpacing, snapRect } = event;\n\n const topAlignLines = this.calcDirectionAlignLines({\n alignRects: alignRects.top,\n targetRect: snapRect,\n isVertical: true,\n spacing: alignSpacing.midVertical ?? alignSpacing.top,\n });\n\n const bottomAlignLines = this.calcDirectionAlignLines({\n alignRects: alignRects.bottom,\n targetRect: snapRect,\n isVertical: true,\n spacing: alignSpacing.midVertical ?? alignSpacing.bottom,\n });\n\n const leftAlignLines = this.calcDirectionAlignLines({\n alignRects: alignRects.left,\n targetRect: snapRect,\n isVertical: false,\n spacing: alignSpacing.midHorizontal ?? alignSpacing.left,\n });\n\n const rightAlignLines = this.calcDirectionAlignLines({\n alignRects: alignRects.right,\n targetRect: snapRect,\n isVertical: false,\n spacing: alignSpacing.midHorizontal ?? alignSpacing.right,\n });\n\n return [...topAlignLines, ...bottomAlignLines, ...leftAlignLines, ...rightAlignLines];\n }\n\n private calcDirectionAlignLines(params: {\n alignRects: AlignRect[];\n targetRect: Rectangle;\n isVertical: boolean;\n spacing?: number;\n }) {\n const { alignRects, targetRect, isVertical, spacing } = params;\n const alignLines: SnapRenderLine[] = [];\n if (!spacing) {\n return alignLines;\n }\n for (let i = 0; i < alignRects.length; i++) {\n const alignRect = alignRects[i];\n const rect = alignRect.rect;\n const prevRect = alignRects[i - 1]?.rect ?? targetRect;\n\n const betweenSpacing = isVertical\n ? Math.min(Math.abs(prevRect.top - rect.bottom), Math.abs(prevRect.bottom - rect.top))\n : Math.min(Math.abs(prevRect.left - rect.right), Math.abs(prevRect.right - rect.left));\n if (!isEqual(betweenSpacing, spacing)) {\n // 不连续,需要中断\n break; // 因为要用到 break,所以不能用 Array.map()\n }\n if (isVertical) {\n const centerX = this.calcHorizontalIntersectionCenter(rect, targetRect);\n alignLines.push({\n className: 'align-vertical',\n sourceNode: alignRect.sourceNodeId,\n top: Math.min(rect.bottom, prevRect.bottom),\n left: centerX,\n width: 1,\n height: spacing,\n });\n } else {\n const centerY = this.calcVerticalIntersectionCenter(rect, targetRect);\n alignLines.push({\n className: 'align-horizontal',\n sourceNode: alignRect.sourceNodeId,\n top: centerY,\n left: Math.min(rect.right, prevRect.right),\n width: spacing,\n height: 1,\n });\n }\n }\n return alignLines;\n }\n\n private calcVerticalIntersectionCenter(rectA: Rectangle, rectB: Rectangle): number {\n const top = Math.max(rectA.top, rectB.top);\n const bottom = Math.min(rectA.bottom, rectB.bottom);\n return (top + bottom) / 2;\n }\n\n private calcHorizontalIntersectionCenter(rectA: Rectangle, rectB: Rectangle): number {\n const left = Math.max(rectA.left, rectB.left);\n const right = Math.min(rectA.right, rectB.right);\n return (left + right) / 2;\n }\n}\n"],"mappings":"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","names":["inject","injectable","WorkflowDocument","FlowNodeTransformData","FlowNodeTransformData","inject","WorkflowDocument","injectable"]}
|
|
1
|
+
{"version":3,"sources":["../../src/create-plugin.ts","../../src/service.ts","../../src/constant.ts","../../src/utils.ts","../../src/layer.tsx"],"sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { definePluginCreator } from '@flowgram.ai/core';\n\nimport {\n FreeSnapPluginOptions,\n WorkflowSnapLayerOptions,\n WorkflowSnapServiceOptions,\n} from './type';\nimport { WorkflowSnapService } from './service';\nimport { WorkflowSnapLayer } from './layer';\nimport { SnapDefaultOptions } from './constant';\n\nexport const createFreeSnapPlugin = definePluginCreator<FreeSnapPluginOptions>({\n onBind({ bind }) {\n bind(WorkflowSnapService).toSelf().inSingletonScope();\n },\n onInit(ctx, opts) {\n const options: WorkflowSnapServiceOptions & WorkflowSnapLayerOptions = {\n ...SnapDefaultOptions,\n ...opts,\n };\n ctx.playground.registerLayer(WorkflowSnapLayer, options);\n const snapService = ctx.get<WorkflowSnapService>(WorkflowSnapService);\n snapService.init(options);\n },\n onDispose(ctx) {\n const snapService = ctx.get<WorkflowSnapService>(WorkflowSnapService);\n snapService.dispose();\n },\n});\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { inject, injectable } from 'inversify';\nimport { Disposable, Emitter, Rectangle } from '@flowgram.ai/utils';\nimport { IPoint } from '@flowgram.ai/utils';\nimport { WorkflowNodeEntity, WorkflowDocument } from '@flowgram.ai/free-layout-core';\nimport { WorkflowDragService } from '@flowgram.ai/free-layout-core';\nimport { FlowNodeTransformData } from '@flowgram.ai/document';\nimport { FlowNodeBaseType } from '@flowgram.ai/document';\nimport { EntityManager, PlaygroundConfigEntity, TransformData } from '@flowgram.ai/core';\n\nimport { isEqual, isGreaterThan, isLessThan, isLessThanOrEqual, isNumber } from './utils';\nimport type {\n SnapEvent,\n SnapHorizontalLine,\n SnapLines,\n SnapMidHorizontalLine,\n SnapMidVerticalLine,\n SnapVerticalLine,\n WorkflowSnapServiceOptions,\n AlignRects,\n AlignRect,\n AlignSpacing,\n SnapNodeRect,\n SnapEdgeLines,\n} from './type';\nimport { SnapDefaultOptions } from './constant';\n\n@injectable()\nexport class WorkflowSnapService {\n @inject(WorkflowDocument) private readonly document: WorkflowDocument;\n\n @inject(EntityManager) private readonly entityManager: EntityManager;\n\n @inject(WorkflowDragService)\n private readonly dragService: WorkflowDragService;\n\n @inject(PlaygroundConfigEntity)\n private readonly playgroundConfig: PlaygroundConfigEntity;\n\n private disposers: Disposable[] = [];\n\n private options: WorkflowSnapServiceOptions;\n\n private snapEmitter = new Emitter<SnapEvent>();\n\n public readonly onSnap = this.snapEmitter.event;\n\n private _disabled = false;\n\n public init(params: Partial<WorkflowSnapServiceOptions> = {}): void {\n this.options = {\n ...SnapDefaultOptions,\n ...params,\n };\n this.mountListener();\n }\n\n public dispose(): void {\n this.disposers.forEach((disposer) => disposer.dispose());\n }\n\n public get disabled(): boolean {\n return this._disabled;\n }\n\n public disable(): void {\n if (this._disabled) {\n return;\n }\n this._disabled = true;\n this.clear();\n }\n\n public enable(): void {\n if (!this._disabled) {\n return;\n }\n this._disabled = false;\n this.clear();\n }\n\n private mountListener(): void {\n const dragAdjusterDisposer = this.dragService.registerPosAdjuster((params) => {\n const { selectedNodes: targetNodes, position } = params;\n const isMultiSnapping = this.options.enableMultiSnapping ? false : targetNodes.length !== 1;\n if (this._disabled || !this.options.enableEdgeSnapping || isMultiSnapping) {\n return {\n x: 0,\n y: 0,\n };\n }\n return this.snapping({\n targetNodes,\n position,\n });\n });\n const dragEndDisposer = this.dragService.onNodesDrag((event) => {\n if (event.type !== 'onDragEnd' || this._disabled) {\n return;\n }\n if (this.options.enableGridSnapping) {\n this.gridSnapping({\n targetNodes: event.nodes,\n gridSize: this.options.gridSize,\n });\n }\n if (this.options.enableEdgeSnapping) {\n this.clear();\n }\n });\n this.disposers.push(dragAdjusterDisposer, dragEndDisposer);\n }\n\n private snapping(params: { targetNodes: WorkflowNodeEntity[]; position: IPoint }): IPoint {\n const { targetNodes, position } = params;\n\n const targetBounds = this.getBounds(targetNodes);\n\n const targetRect = new Rectangle(\n position.x,\n position.y,\n targetBounds.width,\n targetBounds.height\n );\n\n const snapNodeRects = this.getSnapNodeRects({\n targetNodes,\n targetRect,\n });\n\n const { alignOffset, alignRects, alignSpacing } = this.calcAlignOffset({\n targetRect,\n alignThreshold: this.options.edgeThreshold,\n snapNodeRects,\n });\n\n const { snapOffset, snapEdgeLines } = this.calcSnapOffset({\n targetRect,\n edgeThreshold: this.options.edgeThreshold,\n snapNodeRects,\n });\n\n const offset: IPoint = {\n x: snapOffset.x || alignOffset.x,\n y: snapOffset.y || alignOffset.y,\n };\n\n const snapRect = new Rectangle(\n position.x + offset.x,\n position.y + offset.y,\n targetRect.width,\n targetRect.height\n );\n\n this.snapEmitter.fire({\n snapRect,\n snapEdgeLines,\n alignRects,\n alignSpacing,\n });\n\n return offset;\n }\n\n private calcSnapOffset(params: {\n snapNodeRects: SnapNodeRect[];\n targetRect: Rectangle;\n edgeThreshold: number;\n }): {\n snapOffset: IPoint;\n snapEdgeLines: SnapEdgeLines;\n } {\n const { snapNodeRects, edgeThreshold, targetRect } = params;\n\n const snapLines = this.getSnapLines({\n snapNodeRects,\n });\n\n // 找到最近的线条\n const topYClosestLine = snapLines.horizontal.find((line) =>\n isLessThanOrEqual(Math.abs(line.y - targetRect.top), edgeThreshold)\n );\n const bottomYClosestLine = snapLines.horizontal.find((line) =>\n isLessThanOrEqual(Math.abs(line.y - targetRect.bottom), edgeThreshold)\n );\n const leftXClosestLine = snapLines.vertical.find((line) =>\n isLessThanOrEqual(Math.abs(line.x - targetRect.left), edgeThreshold)\n );\n const rightXClosestLine = snapLines.vertical.find((line) =>\n isLessThanOrEqual(Math.abs(line.x - targetRect.right), edgeThreshold)\n );\n const midYClosestLine = snapLines.midHorizontal.find((line) =>\n isLessThanOrEqual(Math.abs(line.y - targetRect.center.y), edgeThreshold)\n );\n const midXClosestLine = snapLines.midVertical.find((line) =>\n isLessThanOrEqual(Math.abs(line.x - targetRect.center.x), edgeThreshold)\n );\n\n // 计算最近坐标\n const topYClosest = topYClosestLine?.y;\n const bottomYClosest = isNumber(bottomYClosestLine?.y)\n ? bottomYClosestLine!.y - targetRect.height\n : undefined;\n const leftXClosest = leftXClosestLine?.x;\n const rightXClosest = isNumber(rightXClosestLine?.x)\n ? rightXClosestLine!.x - targetRect.width\n : undefined;\n const midYClosest = isNumber(midYClosestLine?.y)\n ? midYClosestLine!.y - targetRect.height / 2\n : undefined;\n const midXClosest = isNumber(midXClosestLine?.x)\n ? midXClosestLine!.x - targetRect.width / 2\n : undefined;\n\n // 吸附后坐标,按优先级取值\n const snappingPosition = {\n x: midXClosest ?? leftXClosest ?? rightXClosest ?? targetRect.x,\n y: midYClosest ?? topYClosest ?? bottomYClosest ?? targetRect.y,\n };\n\n // 吸附修正偏移量\n const snapOffset: IPoint = {\n x: snappingPosition.x - targetRect.x,\n y: snappingPosition.y - targetRect.y,\n };\n\n // 生效的吸附线条\n const snapEdgeLines: SnapEdgeLines = {\n top: isEqual(topYClosest, snappingPosition.y) ? topYClosestLine : undefined,\n bottom: isEqual(bottomYClosest, snappingPosition.y) ? bottomYClosestLine : undefined,\n left: isEqual(leftXClosest, snappingPosition.x) ? leftXClosestLine : undefined,\n right: isEqual(rightXClosest, snappingPosition.x) ? rightXClosestLine : undefined,\n midVertical: isEqual(midXClosest, snappingPosition.x) ? midXClosestLine : undefined,\n midHorizontal: isEqual(midYClosest, snappingPosition.y) ? midYClosestLine : undefined,\n };\n\n return { snapOffset, snapEdgeLines };\n }\n\n private gridSnapping(params: { gridSize: number; targetNodes: WorkflowNodeEntity[] }): void {\n const { gridSize, targetNodes } = params;\n const rect = this.getBounds(targetNodes);\n const snap = (value: number) => Math.round(value / gridSize) * gridSize;\n const snappedPosition: IPoint = {\n x: snap(rect.x),\n y: snap(rect.y),\n };\n const offset: IPoint = {\n x: snappedPosition.x - rect.x,\n y: snappedPosition.y - rect.y,\n };\n targetNodes.forEach((node) =>\n this.updateNodePositionWithOffset({\n node,\n offset,\n })\n );\n }\n\n private clear() {\n this.snapEmitter.fire({\n snapEdgeLines: {},\n snapRect: Rectangle.EMPTY,\n alignRects: {\n top: [],\n bottom: [],\n left: [],\n right: [],\n },\n alignSpacing: {},\n });\n }\n\n private getSnapLines(params: { snapNodeRects: SnapNodeRect[] }): SnapLines {\n const { snapNodeRects } = params;\n const horizontalLines: SnapHorizontalLine[] = [];\n const verticalLines: SnapVerticalLine[] = [];\n const midHorizontalLines: SnapMidHorizontalLine[] = [];\n const midVerticalLines: SnapMidVerticalLine[] = [];\n\n snapNodeRects.forEach((snapNodeRect) => {\n const nodeBounds = snapNodeRect.rect;\n const nodeCenter = nodeBounds.center;\n // 边缘横线\n const top: SnapHorizontalLine = {\n y: nodeBounds.top,\n sourceNodeId: snapNodeRect.id,\n };\n const bottom: SnapHorizontalLine = {\n y: nodeBounds.bottom,\n sourceNodeId: snapNodeRect.id,\n };\n // 边缘竖线\n const left: SnapVerticalLine = {\n x: nodeBounds.left,\n sourceNodeId: snapNodeRect.id,\n };\n const right: SnapVerticalLine = {\n x: nodeBounds.right,\n sourceNodeId: snapNodeRect.id,\n };\n // 中间横线\n const midHorizontal: SnapMidHorizontalLine = {\n y: nodeCenter.y,\n sourceNodeId: snapNodeRect.id,\n };\n // 中间竖线\n const midVertical: SnapMidVerticalLine = {\n x: nodeCenter.x,\n sourceNodeId: snapNodeRect.id,\n };\n horizontalLines.push(top, bottom);\n verticalLines.push(left, right);\n midHorizontalLines.push(midHorizontal);\n midVerticalLines.push(midVertical);\n });\n\n return {\n horizontal: horizontalLines,\n vertical: verticalLines,\n midHorizontal: midHorizontalLines,\n midVertical: midVerticalLines,\n };\n }\n\n private getAvailableNodes(params: {\n targetNodes: WorkflowNodeEntity[];\n targetRect: Rectangle;\n }): WorkflowNodeEntity[] {\n const { targetNodes, targetRect } = params;\n\n const targetCenter = targetRect.center;\n const targetContainerId = targetNodes[0].parent?.id ?? this.document.root.id;\n\n const disabledNodeIds = targetNodes.map((n) => n.id);\n disabledNodeIds.push(FlowNodeBaseType.ROOT);\n const availableNodes = this.nodes\n .filter((n) => n.parent?.id === targetContainerId)\n .filter((n) => !disabledNodeIds.includes(n.id))\n .sort((nodeA, nodeB) => {\n const nodeCenterA = nodeA.getData(FlowNodeTransformData)!.bounds.center;\n const nodeCenterB = nodeB.getData(FlowNodeTransformData)!.bounds.center;\n // 距离越近优先级越高\n const distanceA =\n Math.abs(nodeCenterA.x - targetCenter.x) + Math.abs(nodeCenterA.y - targetCenter.y);\n const distanceB =\n Math.abs(nodeCenterB.x - targetCenter.x) + Math.abs(nodeCenterB.y - targetCenter.y);\n return distanceA - distanceB;\n });\n return availableNodes;\n }\n\n private viewRect(): Rectangle {\n const { width, height, scrollX, scrollY, zoom } = this.playgroundConfig.config;\n return new Rectangle(scrollX / zoom, scrollY / zoom, width / zoom, height / zoom);\n }\n\n private getSnapNodeRects(params: {\n targetNodes: WorkflowNodeEntity[];\n targetRect: Rectangle;\n }): SnapNodeRect[] {\n const availableNodes = this.getAvailableNodes(params);\n const viewRect = this.viewRect();\n return availableNodes\n .map((node) => {\n const snapNodeRect: SnapNodeRect = {\n id: node.id,\n rect: node.getData(FlowNodeTransformData).bounds,\n entity: node,\n };\n if (\n this.options.enableOnlyViewportSnapping &&\n node.parent?.flowNodeType === FlowNodeBaseType.ROOT &&\n !Rectangle.intersects(viewRect, snapNodeRect.rect)\n ) {\n // 最外层节点仅包含当前可见节点\n return;\n }\n return snapNodeRect;\n })\n .filter(Boolean) as SnapNodeRect[];\n }\n\n private get nodes(): WorkflowNodeEntity[] {\n return this.entityManager.getEntities<WorkflowNodeEntity>(WorkflowNodeEntity);\n }\n\n private getBounds(nodes: WorkflowNodeEntity[]): Rectangle {\n if (nodes.length === 0) {\n return Rectangle.EMPTY;\n }\n return Rectangle.enlarge(nodes.map((n) => n.getData(FlowNodeTransformData)!.bounds));\n }\n\n private updateNodePositionWithOffset(params: { node: WorkflowNodeEntity; offset: IPoint }): void {\n const { node, offset } = params;\n const transform = node.getData(TransformData);\n const positionWithOffset: IPoint = {\n x: transform.position.x + offset.x,\n y: transform.position.y + offset.y,\n };\n transform.update({\n position: positionWithOffset,\n });\n this.document.layout.updateAffectedTransform(node);\n }\n\n private calcAlignOffset(params: {\n snapNodeRects: SnapNodeRect[];\n targetRect: Rectangle;\n alignThreshold: number;\n }): {\n alignOffset: IPoint;\n alignRects: AlignRects;\n alignSpacing: AlignSpacing;\n } {\n const { snapNodeRects, targetRect, alignThreshold } = params;\n\n const alignRects = this.getAlignRects({\n targetRect,\n snapNodeRects,\n });\n\n const alignSpacing = this.calcAlignSpacing({\n targetRect,\n alignRects,\n });\n\n let topY: number | undefined;\n let bottomY: number | undefined;\n let leftX: number | undefined;\n let rightX: number | undefined;\n let midY: number | undefined;\n let midX: number | undefined;\n\n if (alignSpacing.top) {\n const topAlignY = alignRects.top[0].rect.bottom + alignSpacing.top;\n const isAlignTop = isLessThanOrEqual(Math.abs(targetRect.top - topAlignY), alignThreshold);\n if (isAlignTop) {\n // 生效\n topY = topAlignY;\n } else {\n // 失效\n alignSpacing.top = undefined;\n }\n }\n if (alignSpacing.bottom) {\n const bottomAlignY = alignRects.bottom[0].rect.top - alignSpacing.bottom;\n const isAlignBottom = isLessThan(Math.abs(targetRect.bottom - bottomAlignY), alignThreshold);\n if (isAlignBottom) {\n bottomY = bottomAlignY - targetRect.height;\n } else {\n alignSpacing.bottom = undefined;\n }\n }\n if (alignSpacing.left) {\n const leftAlignX = alignRects.left[0].rect.right + alignSpacing.left;\n const isAlignLeft = isLessThanOrEqual(Math.abs(targetRect.left - leftAlignX), alignThreshold);\n if (isAlignLeft) {\n leftX = leftAlignX;\n } else {\n alignSpacing.left = undefined;\n }\n }\n if (alignSpacing.right) {\n const rightAlignX = alignRects.right[0].rect.left - alignSpacing.right;\n const isAlignRight = isLessThanOrEqual(\n Math.abs(targetRect.right - rightAlignX),\n alignThreshold\n );\n if (isAlignRight) {\n rightX = rightAlignX - targetRect.width;\n } else {\n alignSpacing.right = undefined;\n }\n }\n if (alignSpacing.midHorizontal) {\n const leftAlignX = alignRects.left[0].rect.right + alignSpacing.midHorizontal;\n const isAlignMidHorizontal = isLessThanOrEqual(\n Math.abs(targetRect.left - leftAlignX),\n alignThreshold\n );\n if (isAlignMidHorizontal) {\n midX = leftAlignX;\n } else {\n alignSpacing.midHorizontal = undefined;\n }\n }\n if (alignSpacing.midVertical) {\n const topAlignY = alignRects.top[0].rect.bottom + alignSpacing.midVertical;\n const isAlignMidVertical = isLessThanOrEqual(\n Math.abs(targetRect.top - topAlignY),\n alignThreshold\n );\n if (isAlignMidVertical) {\n midY = topAlignY;\n } else {\n alignSpacing.midVertical = undefined;\n }\n }\n\n const alignPosition: IPoint = {\n x: midX ?? leftX ?? rightX ?? targetRect.x,\n y: midY ?? topY ?? bottomY ?? targetRect.y,\n };\n\n const alignOffset: IPoint = {\n x: alignPosition.x - targetRect.x,\n y: alignPosition.y - targetRect.y,\n };\n\n return { alignOffset, alignRects, alignSpacing };\n }\n\n private calcAlignSpacing(params: {\n targetRect: Rectangle;\n alignRects: AlignRects;\n }): AlignSpacing {\n const { targetRect, alignRects } = params;\n\n const topSpacing = this.getDirectionAlignSpacing({\n rects: alignRects.top,\n isHorizontal: false,\n });\n const bottomSpacing = this.getDirectionAlignSpacing({\n rects: alignRects.bottom,\n isHorizontal: false,\n });\n const leftSpacing = this.getDirectionAlignSpacing({\n rects: alignRects.left,\n isHorizontal: true,\n });\n const rightSpacing = this.getDirectionAlignSpacing({\n rects: alignRects.right,\n isHorizontal: true,\n });\n const midHorizontalSpacing = this.getMidAlignSpacing({\n rectA: alignRects.left[0]?.rect,\n rectB: alignRects.right[0]?.rect,\n targetRect,\n isHorizontal: true,\n });\n const midVerticalSpacing = this.getMidAlignSpacing({\n rectA: alignRects.top[0]?.rect,\n rectB: alignRects.bottom[0]?.rect,\n targetRect,\n isHorizontal: false,\n });\n return {\n top: topSpacing,\n bottom: bottomSpacing,\n left: leftSpacing,\n right: rightSpacing,\n midHorizontal: midHorizontalSpacing,\n midVertical: midVerticalSpacing,\n };\n }\n\n private getAlignRects(params: {\n targetRect: Rectangle;\n snapNodeRects: SnapNodeRect[];\n }): AlignRects {\n const { targetRect, snapNodeRects } = params;\n\n const topVerticalRects: AlignRect[] = [];\n const bottomVerticalRects: AlignRect[] = [];\n const leftHorizontalRects: AlignRect[] = [];\n const rightHorizontalRects: AlignRect[] = [];\n\n snapNodeRects.forEach((snapNodeRect) => {\n const nodeRect = snapNodeRect.rect;\n const { isVerticalIntersection, isHorizontalIntersection, isIntersection } =\n this.intersection(nodeRect, targetRect);\n if (isIntersection) {\n // 忽略重叠的节点\n return;\n } else if (isVerticalIntersection) {\n // 垂直重合\n if (isGreaterThan(nodeRect.center.y, targetRect.center.y)) {\n // 下方\n bottomVerticalRects.push({\n rect: nodeRect,\n sourceNodeId: snapNodeRect.id,\n });\n } else {\n // 上方\n topVerticalRects.push({\n rect: nodeRect,\n sourceNodeId: snapNodeRect.id,\n });\n }\n } else if (isHorizontalIntersection) {\n // 水平重合\n if (isGreaterThan(nodeRect.center.x, targetRect.center.x)) {\n // 右方\n rightHorizontalRects.push({\n rect: nodeRect,\n sourceNodeId: snapNodeRect.id,\n });\n } else {\n // 左方\n leftHorizontalRects.push({\n rect: nodeRect,\n sourceNodeId: snapNodeRect.id,\n });\n }\n }\n });\n\n return {\n top: topVerticalRects,\n bottom: bottomVerticalRects,\n left: leftHorizontalRects,\n right: rightHorizontalRects,\n };\n }\n\n private getMidAlignSpacing(params: {\n rectA?: Rectangle;\n rectB?: Rectangle;\n targetRect: Rectangle;\n isHorizontal: boolean;\n }): number | undefined {\n const { rectA, rectB, targetRect, isHorizontal } = params;\n if (!rectA || !rectB) {\n return;\n }\n const { isVerticalIntersection, isHorizontalIntersection, isIntersection } = this.intersection(\n rectA,\n rectB\n );\n if (isIntersection) {\n return;\n }\n if (isHorizontal && isHorizontalIntersection && !isVerticalIntersection) {\n const betweenSpacing = Math.min(\n Math.abs(rectA.left - rectB.right),\n Math.abs(rectA.right - rectB.left)\n );\n return (betweenSpacing - targetRect.width) / 2;\n } else if (!isHorizontal && isVerticalIntersection && !isHorizontalIntersection) {\n const betweenSpacing = Math.min(\n Math.abs(rectA.top - rectB.bottom),\n Math.abs(rectA.bottom - rectB.top)\n );\n return (betweenSpacing - targetRect.height) / 2;\n }\n }\n\n private getDirectionAlignSpacing(params: {\n rects: AlignRect[];\n isHorizontal: boolean;\n }): number | undefined {\n const { rects, isHorizontal } = params;\n if (rects.length < 2) {\n // 非法情况\n return;\n }\n const rectA = rects[0].rect;\n const rectB = rects[1].rect;\n\n const { isVerticalIntersection, isHorizontalIntersection, isIntersection } = this.intersection(\n rectA,\n rectB\n );\n\n if (isIntersection) {\n // 非法情况:重叠\n return;\n }\n if (isHorizontal && isHorizontalIntersection && !isVerticalIntersection) {\n return Math.min(Math.abs(rectA.left - rectB.right), Math.abs(rectA.right - rectB.left));\n } else if (!isHorizontal && isVerticalIntersection && !isHorizontalIntersection) {\n return Math.min(Math.abs(rectA.top - rectB.bottom), Math.abs(rectA.bottom - rectB.top));\n }\n return;\n }\n\n private intersection(\n rectA: Rectangle,\n rectB: Rectangle\n ): {\n isHorizontalIntersection: boolean;\n isVerticalIntersection: boolean;\n isIntersection: boolean;\n } {\n const isVerticalIntersection =\n isLessThan(rectA.left, rectB.right) && isGreaterThan(rectA.right, rectB.left);\n const isHorizontalIntersection =\n isLessThan(rectA.top, rectB.bottom) && isGreaterThan(rectA.bottom, rectB.top);\n const isIntersection = isHorizontalIntersection && isVerticalIntersection;\n\n return {\n isHorizontalIntersection,\n isVerticalIntersection,\n isIntersection,\n };\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport type { WorkflowSnapLayerOptions, WorkflowSnapServiceOptions } from './type';\n\nexport const SnapDefaultOptions: WorkflowSnapServiceOptions & WorkflowSnapLayerOptions = {\n enableEdgeSnapping: true,\n edgeThreshold: 7,\n enableGridSnapping: false,\n gridSize: 20,\n enableMultiSnapping: true,\n enableOnlyViewportSnapping: true,\n edgeColor: '#4E40E5',\n alignColor: '#4E40E5',\n edgeLineWidth: 2,\n alignLineWidth: 2,\n alignCrossWidth: 16,\n};\n\nexport const Epsilon = 0.00001;\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { Epsilon } from './constant';\n\n/** 检查浮点数 a 是否等于 b */\nexport const isEqual = (a: number | undefined, b: number | undefined): boolean => {\n if (a === undefined || b === undefined) {\n return false;\n }\n // 检查 a 和 b 的差的绝对值是否小于 Epsilon\n return Math.abs(a - b) < Epsilon;\n};\n\n/** 检查浮点数 a 是否小于 b */\nexport const isLessThan = (a: number | undefined, b: number | undefined): boolean => {\n if (a === undefined || b === undefined) {\n return false;\n }\n // 检查 a 是否显著小于 b\n return b - a > Epsilon;\n};\n\n/** 检查浮点数 a 是否大于 b */\nexport const isGreaterThan = (a: number | undefined, b: number | undefined): boolean => {\n if (a === undefined || b === undefined) {\n return false;\n }\n return a - b > Epsilon;\n};\n\n/** 检查浮点数 a 是否小于等于 b */\nexport const isLessThanOrEqual = (a: number | undefined, b: number | undefined): boolean =>\n isEqual(a, b) || isLessThan(a, b);\n\n/** 检查浮点数 a 是否大于等于 b */\nexport const isGreaterThanOrEqual = (a: number | undefined, b: number | undefined): boolean =>\n isEqual(a, b) || isGreaterThan(a, b);\n\n/** 检查值是否是数字类型 */\nexport const isNumber = (value: unknown): value is number =>\n typeof value === 'number' && !isNaN(value);\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React from 'react';\n\nimport { inject, injectable } from 'inversify';\nimport { domUtils } from '@flowgram.ai/utils';\nimport { Rectangle } from '@flowgram.ai/utils';\nimport { WorkflowDocument } from '@flowgram.ai/free-layout-core';\nimport { FlowNodeTransformData } from '@flowgram.ai/document';\nimport { Layer } from '@flowgram.ai/core';\n\nimport { isEqual, isGreaterThan, isNumber } from './utils';\nimport { AlignRect, SnapEvent, WorkflowSnapLayerOptions } from './type';\nimport { WorkflowSnapService } from './service';\n\ninterface SnapRenderLine {\n className: string;\n sourceNode: string;\n top: number;\n left: number;\n width: number;\n height: number;\n dashed?: boolean;\n}\n\n@injectable()\nexport class WorkflowSnapLayer extends Layer<WorkflowSnapLayerOptions> {\n public static type = 'WorkflowSnapLayer';\n\n @inject(WorkflowDocument) private readonly document: WorkflowDocument;\n\n @inject(WorkflowSnapService) private readonly service: WorkflowSnapService;\n\n public readonly node = domUtils.createDivWithClass(\n 'gedit-playground-layer gedit-flow-snap-layer'\n );\n\n private edgeLines: SnapRenderLine[] = [];\n\n private alignLines: SnapRenderLine[] = [];\n\n public onReady(): void {\n this.node.style.zIndex = '9999';\n this.toDispose.pushAll([\n this.service.onSnap((event: SnapEvent) => {\n this.edgeLines = this.calcEdgeLines(event);\n this.alignLines = this.calcAlignLines(event);\n this.render();\n }),\n ]);\n }\n\n public render(): JSX.Element {\n return (\n <>\n {this.alignLines.length > 0 && (\n <div className=\"workflow-snap-align-lines\">{this.renderAlignLines()}</div>\n )}\n {this.edgeLines.length > 0 && (\n <div className=\"workflow-snap-edge-lines\">{this.renderEdgeLines()}</div>\n )}\n </>\n );\n }\n\n public onZoom(scale: number): void {\n this.node.style.transform = `scale(${scale})`;\n }\n\n private renderEdgeLines(): JSX.Element[] {\n return this.edgeLines.map((renderLine: SnapRenderLine) => {\n const { className, sourceNode, top, left, width, height, dashed } = renderLine;\n const id = `${className}-${sourceNode}-${top}-${left}-${width}-${height}`;\n const isHorizontal = width < height;\n const border = `${this.options.edgeLineWidth}px ${dashed ? 'dashed' : 'solid'} ${\n this.options.edgeColor\n }`;\n return (\n <div\n className={`workflow-snap-edge-line ${className}`}\n data-testid=\"sdk.workflow.canvas.snap.edgeLine\"\n data-snap-line-id={id}\n data-snap-line-source-node={sourceNode}\n key={id}\n style={{\n top,\n left,\n width,\n height,\n position: 'absolute',\n borderLeft: isHorizontal ? border : 'none',\n borderTop: !isHorizontal ? border : 'none',\n }}\n />\n );\n });\n }\n\n private renderAlignLines(): JSX.Element[] {\n return this.alignLines.map((renderLine: SnapRenderLine) => {\n const id = `${renderLine.className}-${renderLine.sourceNode}-${renderLine.top}-${renderLine.left}-${renderLine.width}-${renderLine.height}`;\n const isHorizontal = isGreaterThan(renderLine.width, renderLine.height);\n const alignLineWidth = this.options.alignLineWidth; // 整体线条粗细\n const alignCrossWidth = this.options.alignCrossWidth; // 工字形横线的长度\n\n // 调整渲染位置以保持居中\n const adjustedTop = isHorizontal ? renderLine.top - alignLineWidth / 2 : renderLine.top;\n const adjustedLeft = isHorizontal ? renderLine.left : renderLine.left - alignLineWidth / 2;\n\n return (\n <div\n className={`workflow-snap-align-line ${renderLine.className}`}\n data-testid=\"sdk.workflow.canvas.snap.alignLine\"\n data-snap-line-id={id}\n data-snap-line-source-node={renderLine.sourceNode}\n key={id}\n style={{\n position: 'absolute',\n }}\n >\n {/* 主线 */}\n <div\n style={{\n position: 'absolute',\n top: adjustedTop,\n left: adjustedLeft,\n width: isHorizontal ? renderLine.width : alignLineWidth,\n height: isHorizontal ? alignLineWidth : renderLine.height,\n backgroundColor: this.options.alignColor,\n }}\n />\n {/* 左端或上端横线 */}\n <div\n style={{\n position: 'absolute',\n top: isHorizontal\n ? adjustedTop - (alignCrossWidth - alignLineWidth) / 2\n : adjustedTop,\n left: isHorizontal\n ? adjustedLeft\n : adjustedLeft - (alignCrossWidth - alignLineWidth) / 2,\n width: isHorizontal ? alignLineWidth : alignCrossWidth,\n height: isHorizontal ? alignCrossWidth : alignLineWidth,\n backgroundColor: this.options.alignColor,\n }}\n />\n {/* 右端或下端横线 */}\n <div\n style={{\n position: 'absolute',\n top: isHorizontal\n ? adjustedTop - (alignCrossWidth - alignLineWidth) / 2\n : adjustedTop + renderLine.height - alignLineWidth,\n left: isHorizontal\n ? adjustedLeft + renderLine.width - alignLineWidth\n : adjustedLeft - (alignCrossWidth - alignLineWidth) / 2,\n width: isHorizontal ? alignLineWidth : alignCrossWidth,\n height: isHorizontal ? alignCrossWidth : alignLineWidth,\n backgroundColor: this.options.alignColor,\n }}\n />\n </div>\n );\n });\n }\n\n private calcEdgeLines(event: SnapEvent): SnapRenderLine[] {\n const { alignRects, snapRect, snapEdgeLines } = event;\n const edgeLines: SnapRenderLine[] = [];\n\n const topFullAlign = this.directionFullAlign({\n alignRects: alignRects.top,\n targetRect: snapRect,\n isVertical: true,\n });\n const bottomFullAlign = this.directionFullAlign({\n alignRects: alignRects.bottom,\n targetRect: snapRect,\n isVertical: true,\n });\n const leftFullAlign = this.directionFullAlign({\n alignRects: alignRects.left,\n targetRect: snapRect,\n isVertical: false,\n });\n const rightFullAlign = this.directionFullAlign({\n alignRects: alignRects.right,\n targetRect: snapRect,\n isVertical: false,\n });\n\n // 处理顶部对齐\n if (topFullAlign) {\n const top = topFullAlign.rect.top;\n const height = bottomFullAlign\n ? snapRect.bottom - snapRect.height / 2 - top\n : snapRect.bottom - top;\n const width = this.options.edgeLineWidth;\n const lineData = {\n top,\n width,\n height,\n };\n edgeLines.push({\n className: 'edge-full-top-left',\n sourceNode: topFullAlign.sourceNodeId,\n left: snapRect.left,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-top-right',\n sourceNode: topFullAlign.sourceNodeId,\n left: snapRect.right,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-top-mid',\n sourceNode: topFullAlign.sourceNodeId,\n left: snapRect.left + snapRect.width / 2,\n dashed: true,\n ...lineData,\n });\n }\n\n // 处理底部对齐\n if (bottomFullAlign) {\n const top = topFullAlign ? snapRect.top + snapRect.height / 2 : snapRect.top;\n const height = bottomFullAlign.rect.bottom - top;\n const width = this.options.edgeLineWidth;\n const lineData = {\n top,\n width,\n height,\n };\n edgeLines.push({\n className: 'edge-full-bottom-left',\n sourceNode: bottomFullAlign.sourceNodeId,\n left: snapRect.left,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-bottom-right',\n sourceNode: bottomFullAlign.sourceNodeId,\n left: snapRect.right,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-bottom-mid',\n sourceNode: bottomFullAlign.sourceNodeId,\n left: snapRect.left + snapRect.width / 2,\n dashed: true,\n ...lineData,\n });\n }\n\n // 处理左侧对齐\n if (leftFullAlign) {\n const left = leftFullAlign.rect.left;\n const width = rightFullAlign\n ? snapRect.right - snapRect.width / 2 - left\n : snapRect.right - left;\n const height = this.options.edgeLineWidth;\n const lineData = {\n left,\n width,\n height,\n };\n edgeLines.push({\n className: 'edge-full-left-top',\n sourceNode: leftFullAlign.sourceNodeId,\n top: snapRect.top,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-left-bottom',\n sourceNode: leftFullAlign.sourceNodeId,\n top: snapRect.bottom,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-left-mid',\n sourceNode: leftFullAlign.sourceNodeId,\n top: snapRect.top + snapRect.height / 2,\n dashed: true,\n ...lineData,\n });\n }\n\n // 处理右侧对齐\n if (rightFullAlign) {\n const left = leftFullAlign ? snapRect.left + snapRect.width / 2 : snapRect.left;\n const width = rightFullAlign.rect.right - left;\n const height = this.options.edgeLineWidth;\n const lineData = {\n left,\n width,\n height,\n };\n edgeLines.push({\n className: 'edge-full-right-top',\n sourceNode: rightFullAlign.sourceNodeId,\n top: snapRect.top,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-right-bottom',\n sourceNode: rightFullAlign.sourceNodeId,\n top: snapRect.bottom,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-right-mid',\n sourceNode: rightFullAlign.sourceNodeId,\n top: snapRect.top + snapRect.height / 2,\n dashed: true,\n ...lineData,\n });\n }\n\n const snappedEdgeLines = Object.entries(snapEdgeLines)\n .map(([direction, snapLine]) => {\n if (!snapLine) {\n return;\n }\n const sourceNode = this.document.getNode(snapLine.sourceNodeId);\n if (!sourceNode) {\n return;\n }\n const nodeRect = sourceNode.getData(FlowNodeTransformData).bounds;\n if (isNumber(snapLine.x)) {\n // 垂直\n const top = Math.min(nodeRect.top, snapRect.top);\n const bottom = Math.max(nodeRect.bottom, snapRect.bottom);\n const height = bottom - top;\n const left = snapLine.x;\n const width = this.options.edgeLineWidth;\n const isMidX = direction === 'midVertical';\n const lineData: SnapRenderLine = {\n className: `edge-snapped-${direction}`,\n sourceNode: snapLine.sourceNodeId,\n top,\n left,\n width,\n height,\n dashed: isMidX,\n };\n const onTop = top === nodeRect.top;\n if (onTop && topFullAlign) {\n return;\n }\n if (!onTop && bottomFullAlign) {\n return;\n }\n return lineData;\n } else if (isNumber(snapLine.y)) {\n // 水平\n const left = Math.min(nodeRect.left, snapRect.left);\n const right = Math.max(nodeRect.right, snapRect.right);\n const width = right - left;\n const top = snapLine.y;\n const height = this.options.edgeLineWidth;\n const isMidY = direction === 'midHorizontal';\n const lineData: SnapRenderLine = {\n className: `edge-snapped-${direction}`,\n sourceNode: snapLine.sourceNodeId,\n top,\n left,\n width,\n height,\n dashed: isMidY,\n };\n const onLeft = left === nodeRect.left;\n if (onLeft && leftFullAlign) {\n return;\n }\n if (!onLeft && rightFullAlign) {\n return;\n }\n return lineData;\n }\n })\n .filter(Boolean) as SnapRenderLine[];\n\n edgeLines.push(...snappedEdgeLines);\n\n return edgeLines;\n }\n\n private directionFullAlign(params: {\n alignRects: AlignRect[];\n targetRect: Rectangle;\n isVertical: boolean;\n }): AlignRect | undefined {\n const { alignRects, targetRect, isVertical } = params;\n let fullAlignIndex = -1;\n for (let i = 0; i < alignRects.length; i++) {\n const alignRect = alignRects[i];\n const prevRect = alignRects[i - 1]?.rect ?? targetRect;\n const isFullAlign = this.rectFullAlign(alignRect.rect, prevRect, isVertical);\n if (!isFullAlign) {\n // 未对齐则中断\n break; // 用 for 循环 + break 反而比 Array.findIndex 实现可读性更好\n }\n fullAlignIndex = i;\n }\n const fullAlignRect = alignRects[fullAlignIndex];\n return fullAlignRect;\n }\n\n private rectFullAlign(rectA: Rectangle, rectB: Rectangle, isVertical: boolean): boolean {\n if (isVertical) {\n return isEqual(rectA.left, rectB.left) && isEqual(rectA.right, rectB.right);\n } else {\n return isEqual(rectA.top, rectB.top) && isEqual(rectA.bottom, rectB.bottom);\n }\n }\n\n private calcAlignLines(event: SnapEvent): SnapRenderLine[] {\n const { alignRects, alignSpacing, snapRect } = event;\n\n const topAlignLines = this.calcDirectionAlignLines({\n alignRects: alignRects.top,\n targetRect: snapRect,\n isVertical: true,\n spacing: alignSpacing.midVertical ?? alignSpacing.top,\n });\n\n const bottomAlignLines = this.calcDirectionAlignLines({\n alignRects: alignRects.bottom,\n targetRect: snapRect,\n isVertical: true,\n spacing: alignSpacing.midVertical ?? alignSpacing.bottom,\n });\n\n const leftAlignLines = this.calcDirectionAlignLines({\n alignRects: alignRects.left,\n targetRect: snapRect,\n isVertical: false,\n spacing: alignSpacing.midHorizontal ?? alignSpacing.left,\n });\n\n const rightAlignLines = this.calcDirectionAlignLines({\n alignRects: alignRects.right,\n targetRect: snapRect,\n isVertical: false,\n spacing: alignSpacing.midHorizontal ?? alignSpacing.right,\n });\n\n return [...topAlignLines, ...bottomAlignLines, ...leftAlignLines, ...rightAlignLines];\n }\n\n private calcDirectionAlignLines(params: {\n alignRects: AlignRect[];\n targetRect: Rectangle;\n isVertical: boolean;\n spacing?: number;\n }) {\n const { alignRects, targetRect, isVertical, spacing } = params;\n const alignLines: SnapRenderLine[] = [];\n if (!spacing) {\n return alignLines;\n }\n for (let i = 0; i < alignRects.length; i++) {\n const alignRect = alignRects[i];\n const rect = alignRect.rect;\n const prevRect = alignRects[i - 1]?.rect ?? targetRect;\n\n const betweenSpacing = isVertical\n ? Math.min(Math.abs(prevRect.top - rect.bottom), Math.abs(prevRect.bottom - rect.top))\n : Math.min(Math.abs(prevRect.left - rect.right), Math.abs(prevRect.right - rect.left));\n if (!isEqual(betweenSpacing, spacing)) {\n // 不连续,需要中断\n break; // 因为要用到 break,所以不能用 Array.map()\n }\n if (isVertical) {\n const centerX = this.calcHorizontalIntersectionCenter(rect, targetRect);\n alignLines.push({\n className: 'align-vertical',\n sourceNode: alignRect.sourceNodeId,\n top: Math.min(rect.bottom, prevRect.bottom),\n left: centerX,\n width: 1,\n height: spacing,\n });\n } else {\n const centerY = this.calcVerticalIntersectionCenter(rect, targetRect);\n alignLines.push({\n className: 'align-horizontal',\n sourceNode: alignRect.sourceNodeId,\n top: centerY,\n left: Math.min(rect.right, prevRect.right),\n width: spacing,\n height: 1,\n });\n }\n }\n return alignLines;\n }\n\n private calcVerticalIntersectionCenter(rectA: Rectangle, rectB: Rectangle): number {\n const top = Math.max(rectA.top, rectB.top);\n const bottom = Math.min(rectA.bottom, rectB.bottom);\n return (top + bottom) / 2;\n }\n\n private calcHorizontalIntersectionCenter(rectA: Rectangle, rectB: Rectangle): number {\n const left = Math.max(rectA.left, rectB.left);\n const right = Math.min(rectA.right, rectB.right);\n return (left + right) / 2;\n }\n}\n"],"mappings":"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","names":["inject","injectable","WorkflowDocument","FlowNodeTransformData","FlowNodeTransformData","inject","WorkflowDocument","injectable"]}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/create-plugin.ts","../src/service.ts","../src/constant.ts","../src/utils.ts","../src/layer.tsx"],"sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport { createFreeSnapPlugin } from './create-plugin';\nexport { WorkflowSnapService } from './service';\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { definePluginCreator } from '@flowgram.ai/core';\n\nimport {\n FreeSnapPluginOptions,\n WorkflowSnapLayerOptions,\n WorkflowSnapServiceOptions,\n} from './type';\nimport { WorkflowSnapService } from './service';\nimport { WorkflowSnapLayer } from './layer';\nimport { SnapDefaultOptions } from './constant';\n\nexport const createFreeSnapPlugin = definePluginCreator<FreeSnapPluginOptions>({\n onBind({ bind }) {\n bind(WorkflowSnapService).toSelf().inSingletonScope();\n },\n onInit(ctx, opts) {\n const options: WorkflowSnapServiceOptions & WorkflowSnapLayerOptions = {\n ...SnapDefaultOptions,\n ...opts,\n };\n ctx.playground.registerLayer(WorkflowSnapLayer, options);\n const snapService = ctx.get<WorkflowSnapService>(WorkflowSnapService);\n snapService.init(options);\n },\n onDispose(ctx) {\n const snapService = ctx.get<WorkflowSnapService>(WorkflowSnapService);\n snapService.dispose();\n },\n});\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { inject, injectable } from 'inversify';\nimport { Disposable, Emitter, Rectangle } from '@flowgram.ai/utils';\nimport { IPoint } from '@flowgram.ai/utils';\nimport { WorkflowNodeEntity, WorkflowDocument } from '@flowgram.ai/free-layout-core';\nimport { WorkflowDragService } from '@flowgram.ai/free-layout-core';\nimport { FlowNodeTransformData } from '@flowgram.ai/document';\nimport { FlowNodeBaseType } from '@flowgram.ai/document';\nimport { EntityManager, PlaygroundConfigEntity, TransformData } from '@flowgram.ai/core';\n\nimport { isEqual, isGreaterThan, isLessThan, isLessThanOrEqual, isNumber } from './utils';\nimport type {\n SnapEvent,\n SnapHorizontalLine,\n SnapLines,\n SnapMidHorizontalLine,\n SnapMidVerticalLine,\n SnapVerticalLine,\n WorkflowSnapServiceOptions,\n AlignRects,\n AlignRect,\n AlignSpacing,\n SnapNodeRect,\n SnapEdgeLines,\n} from './type';\nimport { SnapDefaultOptions } from './constant';\n\n@injectable()\nexport class WorkflowSnapService {\n @inject(WorkflowDocument) private readonly document: WorkflowDocument;\n\n @inject(EntityManager) private readonly entityManager: EntityManager;\n\n @inject(WorkflowDragService)\n private readonly dragService: WorkflowDragService;\n\n @inject(PlaygroundConfigEntity)\n private readonly playgroundConfig: PlaygroundConfigEntity;\n\n private disposers: Disposable[] = [];\n\n private options: WorkflowSnapServiceOptions;\n\n private snapEmitter = new Emitter<SnapEvent>();\n\n public readonly onSnap = this.snapEmitter.event;\n\n private _disabled = false;\n\n public init(params: Partial<WorkflowSnapServiceOptions> = {}): void {\n this.options = {\n ...SnapDefaultOptions,\n ...params,\n };\n this.mountListener();\n }\n\n public dispose(): void {\n this.disposers.forEach((disposer) => disposer.dispose());\n }\n\n public get disabled(): boolean {\n return this._disabled;\n }\n\n public disable(): void {\n if (this._disabled) {\n return;\n }\n this._disabled = true;\n this.clear();\n }\n\n public enable(): void {\n if (!this._disabled) {\n return;\n }\n this._disabled = false;\n this.clear();\n }\n\n private mountListener(): void {\n const dragAdjusterDisposer = this.dragService.registerPosAdjuster((params) => {\n const { selectedNodes: targetNodes, position } = params;\n const isMultiSnapping = this.options.enableMultiSnapping ? false : targetNodes.length !== 1;\n if (this._disabled || !this.options.enableEdgeSnapping || isMultiSnapping) {\n return {\n x: 0,\n y: 0,\n };\n }\n return this.snapping({\n targetNodes,\n position,\n });\n });\n const dragEndDisposer = this.dragService.onNodesDrag((event) => {\n if (event.type !== 'onDragEnd' || this._disabled) {\n return;\n }\n if (this.options.enableGridSnapping) {\n this.gridSnapping({\n targetNodes: event.nodes,\n gridSize: this.options.gridSize,\n });\n }\n if (this.options.enableEdgeSnapping) {\n this.clear();\n }\n });\n this.disposers.push(dragAdjusterDisposer, dragEndDisposer);\n }\n\n private snapping(params: { targetNodes: WorkflowNodeEntity[]; position: IPoint }): IPoint {\n const { targetNodes, position } = params;\n\n const targetBounds = this.getBounds(targetNodes);\n\n const targetRect = new Rectangle(\n position.x,\n position.y,\n targetBounds.width,\n targetBounds.height\n );\n\n const snapNodeRects = this.getSnapNodeRects({\n targetNodes,\n targetRect,\n });\n\n const { alignOffset, alignRects, alignSpacing } = this.calcAlignOffset({\n targetRect,\n alignThreshold: this.options.edgeThreshold,\n snapNodeRects,\n });\n\n const { snapOffset, snapEdgeLines } = this.calcSnapOffset({\n targetRect,\n edgeThreshold: this.options.edgeThreshold,\n snapNodeRects,\n });\n\n const offset: IPoint = {\n x: snapOffset.x || alignOffset.x,\n y: snapOffset.y || alignOffset.y,\n };\n\n const snapRect = new Rectangle(\n position.x + offset.x,\n position.y + offset.y,\n targetRect.width,\n targetRect.height\n );\n\n this.snapEmitter.fire({\n snapRect,\n snapEdgeLines,\n alignRects,\n alignSpacing,\n });\n\n return offset;\n }\n\n private calcSnapOffset(params: {\n snapNodeRects: SnapNodeRect[];\n targetRect: Rectangle;\n edgeThreshold: number;\n }): {\n snapOffset: IPoint;\n snapEdgeLines: SnapEdgeLines;\n } {\n const { snapNodeRects, edgeThreshold, targetRect } = params;\n\n const snapLines = this.getSnapLines({\n snapNodeRects,\n });\n\n // 找到最近的线条\n const topYClosestLine = snapLines.horizontal.find((line) =>\n isLessThanOrEqual(Math.abs(line.y - targetRect.top), edgeThreshold)\n );\n const bottomYClosestLine = snapLines.horizontal.find((line) =>\n isLessThanOrEqual(Math.abs(line.y - targetRect.bottom), edgeThreshold)\n );\n const leftXClosestLine = snapLines.vertical.find((line) =>\n isLessThanOrEqual(Math.abs(line.x - targetRect.left), edgeThreshold)\n );\n const rightXClosestLine = snapLines.vertical.find((line) =>\n isLessThanOrEqual(Math.abs(line.x - targetRect.right), edgeThreshold)\n );\n const midYClosestLine = snapLines.midHorizontal.find((line) =>\n isLessThanOrEqual(Math.abs(line.y - targetRect.center.y), edgeThreshold)\n );\n const midXClosestLine = snapLines.midVertical.find((line) =>\n isLessThanOrEqual(Math.abs(line.x - targetRect.center.x), edgeThreshold)\n );\n\n // 计算最近坐标\n const topYClosest = topYClosestLine?.y;\n const bottomYClosest = isNumber(bottomYClosestLine?.y)\n ? bottomYClosestLine!.y - targetRect.height\n : undefined;\n const leftXClosest = leftXClosestLine?.x;\n const rightXClosest = isNumber(rightXClosestLine?.x)\n ? rightXClosestLine!.x - targetRect.width\n : undefined;\n const midYClosest = isNumber(midYClosestLine?.y)\n ? midYClosestLine!.y - targetRect.height / 2\n : undefined;\n const midXClosest = isNumber(midXClosestLine?.x)\n ? midXClosestLine!.x - targetRect.width / 2\n : undefined;\n\n // 吸附后坐标,按优先级取值\n const snappingPosition = {\n x: midXClosest ?? leftXClosest ?? rightXClosest ?? targetRect.x,\n y: midYClosest ?? topYClosest ?? bottomYClosest ?? targetRect.y,\n };\n\n // 吸附修正偏移量\n const snapOffset: IPoint = {\n x: snappingPosition.x - targetRect.x,\n y: snappingPosition.y - targetRect.y,\n };\n\n // 生效的吸附线条\n const snapEdgeLines: SnapEdgeLines = {\n top: isEqual(topYClosest, snappingPosition.y) ? topYClosestLine : undefined,\n bottom: isEqual(bottomYClosest, snappingPosition.y) ? bottomYClosestLine : undefined,\n left: isEqual(leftXClosest, snappingPosition.x) ? leftXClosestLine : undefined,\n right: isEqual(rightXClosest, snappingPosition.x) ? rightXClosestLine : undefined,\n midVertical: isEqual(midXClosest, snappingPosition.x) ? midXClosestLine : undefined,\n midHorizontal: isEqual(midYClosest, snappingPosition.y) ? midYClosestLine : undefined,\n };\n\n return { snapOffset, snapEdgeLines };\n }\n\n private gridSnapping(params: { gridSize: number; targetNodes: WorkflowNodeEntity[] }): void {\n const { gridSize, targetNodes } = params;\n const rect = this.getBounds(targetNodes);\n const snap = (value: number) => Math.round(value / gridSize) * gridSize;\n const snappedPosition: IPoint = {\n x: snap(rect.x),\n y: snap(rect.y),\n };\n const offset: IPoint = {\n x: snappedPosition.x - rect.x,\n y: snappedPosition.y - rect.y,\n };\n targetNodes.forEach((node) =>\n this.updateNodePositionWithOffset({\n node,\n offset,\n })\n );\n }\n\n private clear() {\n this.snapEmitter.fire({\n snapEdgeLines: {},\n snapRect: Rectangle.EMPTY,\n alignRects: {\n top: [],\n bottom: [],\n left: [],\n right: [],\n },\n alignSpacing: {},\n });\n }\n\n private getSnapLines(params: { snapNodeRects: SnapNodeRect[] }): SnapLines {\n const { snapNodeRects } = params;\n const horizontalLines: SnapHorizontalLine[] = [];\n const verticalLines: SnapVerticalLine[] = [];\n const midHorizontalLines: SnapMidHorizontalLine[] = [];\n const midVerticalLines: SnapMidVerticalLine[] = [];\n\n snapNodeRects.forEach((snapNodeRect) => {\n const nodeBounds = snapNodeRect.rect;\n const nodeCenter = nodeBounds.center;\n // 边缘横线\n const top: SnapHorizontalLine = {\n y: nodeBounds.top,\n sourceNodeId: snapNodeRect.id,\n };\n const bottom: SnapHorizontalLine = {\n y: nodeBounds.bottom,\n sourceNodeId: snapNodeRect.id,\n };\n // 边缘竖线\n const left: SnapVerticalLine = {\n x: nodeBounds.left,\n sourceNodeId: snapNodeRect.id,\n };\n const right: SnapVerticalLine = {\n x: nodeBounds.right,\n sourceNodeId: snapNodeRect.id,\n };\n // 中间横线\n const midHorizontal: SnapMidHorizontalLine = {\n y: nodeCenter.y,\n sourceNodeId: snapNodeRect.id,\n };\n // 中间竖线\n const midVertical: SnapMidVerticalLine = {\n x: nodeCenter.x,\n sourceNodeId: snapNodeRect.id,\n };\n horizontalLines.push(top, bottom);\n verticalLines.push(left, right);\n midHorizontalLines.push(midHorizontal);\n midVerticalLines.push(midVertical);\n });\n\n return {\n horizontal: horizontalLines,\n vertical: verticalLines,\n midHorizontal: midHorizontalLines,\n midVertical: midVerticalLines,\n };\n }\n\n private getAvailableNodes(params: {\n targetNodes: WorkflowNodeEntity[];\n targetRect: Rectangle;\n }): WorkflowNodeEntity[] {\n const { targetNodes, targetRect } = params;\n\n const targetCenter = targetRect.center;\n const targetContainerId = targetNodes[0].parent?.id ?? this.document.root.id;\n\n const disabledNodeIds = targetNodes.map((n) => n.id);\n disabledNodeIds.push(FlowNodeBaseType.ROOT);\n const availableNodes = this.nodes\n .filter((n) => n.parent?.id === targetContainerId)\n .filter((n) => !disabledNodeIds.includes(n.id))\n .sort((nodeA, nodeB) => {\n const nodeCenterA = nodeA.getData(FlowNodeTransformData)!.bounds.center;\n const nodeCenterB = nodeB.getData(FlowNodeTransformData)!.bounds.center;\n // 距离越近优先级越高\n const distanceA =\n Math.abs(nodeCenterA.x - targetCenter.x) + Math.abs(nodeCenterA.y - targetCenter.y);\n const distanceB =\n Math.abs(nodeCenterB.x - targetCenter.x) + Math.abs(nodeCenterB.y - targetCenter.y);\n return distanceA - distanceB;\n });\n return availableNodes;\n }\n\n private viewRect(): Rectangle {\n const { width, height, scrollX, scrollY, zoom } = this.playgroundConfig.config;\n return new Rectangle(scrollX / zoom, scrollY / zoom, width / zoom, height / zoom);\n }\n\n private getSnapNodeRects(params: {\n targetNodes: WorkflowNodeEntity[];\n targetRect: Rectangle;\n }): SnapNodeRect[] {\n const availableNodes = this.getAvailableNodes(params);\n const viewRect = this.viewRect();\n return availableNodes\n .map((node) => {\n const snapNodeRect: SnapNodeRect = {\n id: node.id,\n rect: node.getData(FlowNodeTransformData).bounds,\n entity: node,\n };\n if (\n this.options.enableOnlyViewportSnapping &&\n node.parent?.flowNodeType === FlowNodeBaseType.ROOT &&\n !Rectangle.intersects(viewRect, snapNodeRect.rect)\n ) {\n // 最外层节点仅包含当前可见节点\n return;\n }\n return snapNodeRect;\n })\n .filter(Boolean) as SnapNodeRect[];\n }\n\n private get nodes(): WorkflowNodeEntity[] {\n return this.entityManager.getEntities<WorkflowNodeEntity>(WorkflowNodeEntity);\n }\n\n private getBounds(nodes: WorkflowNodeEntity[]): Rectangle {\n if (nodes.length === 0) {\n return Rectangle.EMPTY;\n }\n return Rectangle.enlarge(nodes.map((n) => n.getData(FlowNodeTransformData)!.bounds));\n }\n\n private updateNodePositionWithOffset(params: { node: WorkflowNodeEntity; offset: IPoint }): void {\n const { node, offset } = params;\n const transform = node.getData(TransformData);\n const positionWithOffset: IPoint = {\n x: transform.position.x + offset.x,\n y: transform.position.y + offset.y,\n };\n transform.update({\n position: positionWithOffset,\n });\n this.document.layout.updateAffectedTransform(node);\n }\n\n private calcAlignOffset(params: {\n snapNodeRects: SnapNodeRect[];\n targetRect: Rectangle;\n alignThreshold: number;\n }): {\n alignOffset: IPoint;\n alignRects: AlignRects;\n alignSpacing: AlignSpacing;\n } {\n const { snapNodeRects, targetRect, alignThreshold } = params;\n\n const alignRects = this.getAlignRects({\n targetRect,\n snapNodeRects,\n });\n\n const alignSpacing = this.calcAlignSpacing({\n targetRect,\n alignRects,\n });\n\n let topY: number | undefined;\n let bottomY: number | undefined;\n let leftX: number | undefined;\n let rightX: number | undefined;\n let midY: number | undefined;\n let midX: number | undefined;\n\n if (alignSpacing.top) {\n const topAlignY = alignRects.top[0].rect.bottom + alignSpacing.top;\n const isAlignTop = isLessThanOrEqual(Math.abs(targetRect.top - topAlignY), alignThreshold);\n if (isAlignTop) {\n // 生效\n topY = topAlignY;\n } else {\n // 失效\n alignSpacing.top = undefined;\n }\n }\n if (alignSpacing.bottom) {\n const bottomAlignY = alignRects.bottom[0].rect.top - alignSpacing.bottom;\n const isAlignBottom = isLessThan(Math.abs(targetRect.bottom - bottomAlignY), alignThreshold);\n if (isAlignBottom) {\n bottomY = bottomAlignY - targetRect.height;\n } else {\n alignSpacing.bottom = undefined;\n }\n }\n if (alignSpacing.left) {\n const leftAlignX = alignRects.left[0].rect.right + alignSpacing.left;\n const isAlignLeft = isLessThanOrEqual(Math.abs(targetRect.left - leftAlignX), alignThreshold);\n if (isAlignLeft) {\n leftX = leftAlignX;\n } else {\n alignSpacing.left = undefined;\n }\n }\n if (alignSpacing.right) {\n const rightAlignX = alignRects.right[0].rect.left - alignSpacing.right;\n const isAlignRight = isLessThanOrEqual(\n Math.abs(targetRect.right - rightAlignX),\n alignThreshold\n );\n if (isAlignRight) {\n rightX = rightAlignX - targetRect.width;\n } else {\n alignSpacing.right = undefined;\n }\n }\n if (alignSpacing.midHorizontal) {\n const leftAlignX = alignRects.left[0].rect.right + alignSpacing.midHorizontal;\n const isAlignMidHorizontal = isLessThanOrEqual(\n Math.abs(targetRect.left - leftAlignX),\n alignThreshold\n );\n if (isAlignMidHorizontal) {\n midX = leftAlignX;\n } else {\n alignSpacing.midHorizontal = undefined;\n }\n }\n if (alignSpacing.midVertical) {\n const topAlignY = alignRects.top[0].rect.bottom + alignSpacing.midVertical;\n const isAlignMidVertical = isLessThanOrEqual(\n Math.abs(targetRect.top - topAlignY),\n alignThreshold\n );\n if (isAlignMidVertical) {\n midY = topAlignY;\n } else {\n alignSpacing.midVertical = undefined;\n }\n }\n\n const alignPosition: IPoint = {\n x: midX ?? leftX ?? rightX ?? targetRect.x,\n y: midY ?? topY ?? bottomY ?? targetRect.y,\n };\n\n const alignOffset: IPoint = {\n x: alignPosition.x - targetRect.x,\n y: alignPosition.y - targetRect.y,\n };\n\n return { alignOffset, alignRects, alignSpacing };\n }\n\n private calcAlignSpacing(params: {\n targetRect: Rectangle;\n alignRects: AlignRects;\n }): AlignSpacing {\n const { targetRect, alignRects } = params;\n\n const topSpacing = this.getDirectionAlignSpacing({\n rects: alignRects.top,\n isHorizontal: false,\n });\n const bottomSpacing = this.getDirectionAlignSpacing({\n rects: alignRects.bottom,\n isHorizontal: false,\n });\n const leftSpacing = this.getDirectionAlignSpacing({\n rects: alignRects.left,\n isHorizontal: true,\n });\n const rightSpacing = this.getDirectionAlignSpacing({\n rects: alignRects.right,\n isHorizontal: true,\n });\n const midHorizontalSpacing = this.getMidAlignSpacing({\n rectA: alignRects.left[0]?.rect,\n rectB: alignRects.right[0]?.rect,\n targetRect,\n isHorizontal: true,\n });\n const midVerticalSpacing = this.getMidAlignSpacing({\n rectA: alignRects.top[0]?.rect,\n rectB: alignRects.bottom[0]?.rect,\n targetRect,\n isHorizontal: false,\n });\n return {\n top: topSpacing,\n bottom: bottomSpacing,\n left: leftSpacing,\n right: rightSpacing,\n midHorizontal: midHorizontalSpacing,\n midVertical: midVerticalSpacing,\n };\n }\n\n private getAlignRects(params: {\n targetRect: Rectangle;\n snapNodeRects: SnapNodeRect[];\n }): AlignRects {\n const { targetRect, snapNodeRects } = params;\n\n const topVerticalRects: AlignRect[] = [];\n const bottomVerticalRects: AlignRect[] = [];\n const leftHorizontalRects: AlignRect[] = [];\n const rightHorizontalRects: AlignRect[] = [];\n\n snapNodeRects.forEach((snapNodeRect) => {\n const nodeRect = snapNodeRect.rect;\n const { isVerticalIntersection, isHorizontalIntersection, isIntersection } =\n this.intersection(nodeRect, targetRect);\n if (isIntersection) {\n // 忽略重叠的节点\n return;\n } else if (isVerticalIntersection) {\n // 垂直重合\n if (isGreaterThan(nodeRect.center.y, targetRect.center.y)) {\n // 下方\n bottomVerticalRects.push({\n rect: nodeRect,\n sourceNodeId: snapNodeRect.id,\n });\n } else {\n // 上方\n topVerticalRects.push({\n rect: nodeRect,\n sourceNodeId: snapNodeRect.id,\n });\n }\n } else if (isHorizontalIntersection) {\n // 水平重合\n if (isGreaterThan(nodeRect.center.x, targetRect.center.x)) {\n // 右方\n rightHorizontalRects.push({\n rect: nodeRect,\n sourceNodeId: snapNodeRect.id,\n });\n } else {\n // 左方\n leftHorizontalRects.push({\n rect: nodeRect,\n sourceNodeId: snapNodeRect.id,\n });\n }\n }\n });\n\n return {\n top: topVerticalRects,\n bottom: bottomVerticalRects,\n left: leftHorizontalRects,\n right: rightHorizontalRects,\n };\n }\n\n private getMidAlignSpacing(params: {\n rectA?: Rectangle;\n rectB?: Rectangle;\n targetRect: Rectangle;\n isHorizontal: boolean;\n }): number | undefined {\n const { rectA, rectB, targetRect, isHorizontal } = params;\n if (!rectA || !rectB) {\n return;\n }\n const { isVerticalIntersection, isHorizontalIntersection, isIntersection } = this.intersection(\n rectA,\n rectB\n );\n if (isIntersection) {\n return;\n }\n if (isHorizontal && isHorizontalIntersection && !isVerticalIntersection) {\n const betweenSpacing = Math.min(\n Math.abs(rectA.left - rectB.right),\n Math.abs(rectA.right - rectB.left)\n );\n return (betweenSpacing - targetRect.width) / 2;\n } else if (!isHorizontal && isVerticalIntersection && !isHorizontalIntersection) {\n const betweenSpacing = Math.min(\n Math.abs(rectA.top - rectB.bottom),\n Math.abs(rectA.bottom - rectB.top)\n );\n return (betweenSpacing - targetRect.height) / 2;\n }\n }\n\n private getDirectionAlignSpacing(params: {\n rects: AlignRect[];\n isHorizontal: boolean;\n }): number | undefined {\n const { rects, isHorizontal } = params;\n if (rects.length < 2) {\n // 非法情况\n return;\n }\n const rectA = rects[0].rect;\n const rectB = rects[1].rect;\n\n const { isVerticalIntersection, isHorizontalIntersection, isIntersection } = this.intersection(\n rectA,\n rectB\n );\n\n if (isIntersection) {\n // 非法情况:重叠\n return;\n }\n if (isHorizontal && isHorizontalIntersection && !isVerticalIntersection) {\n return Math.min(Math.abs(rectA.left - rectB.right), Math.abs(rectA.right - rectB.left));\n } else if (!isHorizontal && isVerticalIntersection && !isHorizontalIntersection) {\n return Math.min(Math.abs(rectA.top - rectB.bottom), Math.abs(rectA.bottom - rectB.top));\n }\n return;\n }\n\n private intersection(\n rectA: Rectangle,\n rectB: Rectangle\n ): {\n isHorizontalIntersection: boolean;\n isVerticalIntersection: boolean;\n isIntersection: boolean;\n } {\n const isVerticalIntersection =\n isLessThan(rectA.left, rectB.right) && isGreaterThan(rectA.right, rectB.left);\n const isHorizontalIntersection =\n isLessThan(rectA.top, rectB.bottom) && isGreaterThan(rectA.bottom, rectB.top);\n const isIntersection = isHorizontalIntersection && isVerticalIntersection;\n\n return {\n isHorizontalIntersection,\n isVerticalIntersection,\n isIntersection,\n };\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport type { WorkflowSnapLayerOptions, WorkflowSnapServiceOptions } from './type';\n\nexport const SnapDefaultOptions: WorkflowSnapServiceOptions & WorkflowSnapLayerOptions = {\n enableEdgeSnapping: true,\n edgeThreshold: 7,\n enableGridSnapping: false,\n gridSize: 20,\n enableMultiSnapping: false,\n enableOnlyViewportSnapping: true,\n edgeColor: '#4E40E5',\n alignColor: '#4E40E5',\n edgeLineWidth: 2,\n alignLineWidth: 2,\n alignCrossWidth: 16,\n};\n\nexport const Epsilon = 0.00001;\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { Epsilon } from './constant';\n\n/** 检查浮点数 a 是否等于 b */\nexport const isEqual = (a: number | undefined, b: number | undefined): boolean => {\n if (a === undefined || b === undefined) {\n return false;\n }\n // 检查 a 和 b 的差的绝对值是否小于 Epsilon\n return Math.abs(a - b) < Epsilon;\n};\n\n/** 检查浮点数 a 是否小于 b */\nexport const isLessThan = (a: number | undefined, b: number | undefined): boolean => {\n if (a === undefined || b === undefined) {\n return false;\n }\n // 检查 a 是否显著小于 b\n return b - a > Epsilon;\n};\n\n/** 检查浮点数 a 是否大于 b */\nexport const isGreaterThan = (a: number | undefined, b: number | undefined): boolean => {\n if (a === undefined || b === undefined) {\n return false;\n }\n return a - b > Epsilon;\n};\n\n/** 检查浮点数 a 是否小于等于 b */\nexport const isLessThanOrEqual = (a: number | undefined, b: number | undefined): boolean =>\n isEqual(a, b) || isLessThan(a, b);\n\n/** 检查浮点数 a 是否大于等于 b */\nexport const isGreaterThanOrEqual = (a: number | undefined, b: number | undefined): boolean =>\n isEqual(a, b) || isGreaterThan(a, b);\n\n/** 检查值是否是数字类型 */\nexport const isNumber = (value: unknown): value is number =>\n typeof value === 'number' && !isNaN(value);\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React from 'react';\n\nimport { inject, injectable } from 'inversify';\nimport { domUtils } from '@flowgram.ai/utils';\nimport { Rectangle } from '@flowgram.ai/utils';\nimport { WorkflowDocument } from '@flowgram.ai/free-layout-core';\nimport { FlowNodeTransformData } from '@flowgram.ai/document';\nimport { Layer } from '@flowgram.ai/core';\n\nimport { isEqual, isGreaterThan, isNumber } from './utils';\nimport { AlignRect, SnapEvent, WorkflowSnapLayerOptions } from './type';\nimport { WorkflowSnapService } from './service';\n\ninterface SnapRenderLine {\n className: string;\n sourceNode: string;\n top: number;\n left: number;\n width: number;\n height: number;\n dashed?: boolean;\n}\n\n@injectable()\nexport class WorkflowSnapLayer extends Layer<WorkflowSnapLayerOptions> {\n public static type = 'WorkflowSnapLayer';\n\n @inject(WorkflowDocument) private readonly document: WorkflowDocument;\n\n @inject(WorkflowSnapService) private readonly service: WorkflowSnapService;\n\n public readonly node = domUtils.createDivWithClass(\n 'gedit-playground-layer gedit-flow-snap-layer'\n );\n\n private edgeLines: SnapRenderLine[] = [];\n\n private alignLines: SnapRenderLine[] = [];\n\n public onReady(): void {\n this.node.style.zIndex = '9999';\n this.toDispose.pushAll([\n this.service.onSnap((event: SnapEvent) => {\n this.edgeLines = this.calcEdgeLines(event);\n this.alignLines = this.calcAlignLines(event);\n this.render();\n }),\n ]);\n }\n\n public render(): JSX.Element {\n return (\n <>\n {this.alignLines.length > 0 && (\n <div className=\"workflow-snap-align-lines\">{this.renderAlignLines()}</div>\n )}\n {this.edgeLines.length > 0 && (\n <div className=\"workflow-snap-edge-lines\">{this.renderEdgeLines()}</div>\n )}\n </>\n );\n }\n\n public onZoom(scale: number): void {\n this.node.style.transform = `scale(${scale})`;\n }\n\n private renderEdgeLines(): JSX.Element[] {\n return this.edgeLines.map((renderLine: SnapRenderLine) => {\n const { className, sourceNode, top, left, width, height, dashed } = renderLine;\n const id = `${className}-${sourceNode}-${top}-${left}-${width}-${height}`;\n const isHorizontal = width < height;\n const border = `${this.options.edgeLineWidth}px ${dashed ? 'dashed' : 'solid'} ${\n this.options.edgeColor\n }`;\n return (\n <div\n className={`workflow-snap-edge-line ${className}`}\n data-testid=\"sdk.workflow.canvas.snap.edgeLine\"\n data-snap-line-id={id}\n data-snap-line-source-node={sourceNode}\n key={id}\n style={{\n top,\n left,\n width,\n height,\n position: 'absolute',\n borderLeft: isHorizontal ? border : 'none',\n borderTop: !isHorizontal ? border : 'none',\n }}\n />\n );\n });\n }\n\n private renderAlignLines(): JSX.Element[] {\n return this.alignLines.map((renderLine: SnapRenderLine) => {\n const id = `${renderLine.className}-${renderLine.sourceNode}-${renderLine.top}-${renderLine.left}-${renderLine.width}-${renderLine.height}`;\n const isHorizontal = isGreaterThan(renderLine.width, renderLine.height);\n const alignLineWidth = this.options.alignLineWidth; // 整体线条粗细\n const alignCrossWidth = this.options.alignCrossWidth; // 工字形横线的长度\n\n // 调整渲染位置以保持居中\n const adjustedTop = isHorizontal ? renderLine.top - alignLineWidth / 2 : renderLine.top;\n const adjustedLeft = isHorizontal ? renderLine.left : renderLine.left - alignLineWidth / 2;\n\n return (\n <div\n className={`workflow-snap-align-line ${renderLine.className}`}\n data-testid=\"sdk.workflow.canvas.snap.alignLine\"\n data-snap-line-id={id}\n data-snap-line-source-node={renderLine.sourceNode}\n key={id}\n style={{\n position: 'absolute',\n }}\n >\n {/* 主线 */}\n <div\n style={{\n position: 'absolute',\n top: adjustedTop,\n left: adjustedLeft,\n width: isHorizontal ? renderLine.width : alignLineWidth,\n height: isHorizontal ? alignLineWidth : renderLine.height,\n backgroundColor: this.options.alignColor,\n }}\n />\n {/* 左端或上端横线 */}\n <div\n style={{\n position: 'absolute',\n top: isHorizontal\n ? adjustedTop - (alignCrossWidth - alignLineWidth) / 2\n : adjustedTop,\n left: isHorizontal\n ? adjustedLeft\n : adjustedLeft - (alignCrossWidth - alignLineWidth) / 2,\n width: isHorizontal ? alignLineWidth : alignCrossWidth,\n height: isHorizontal ? alignCrossWidth : alignLineWidth,\n backgroundColor: this.options.alignColor,\n }}\n />\n {/* 右端或下端横线 */}\n <div\n style={{\n position: 'absolute',\n top: isHorizontal\n ? adjustedTop - (alignCrossWidth - alignLineWidth) / 2\n : adjustedTop + renderLine.height - alignLineWidth,\n left: isHorizontal\n ? adjustedLeft + renderLine.width - alignLineWidth\n : adjustedLeft - (alignCrossWidth - alignLineWidth) / 2,\n width: isHorizontal ? alignLineWidth : alignCrossWidth,\n height: isHorizontal ? alignCrossWidth : alignLineWidth,\n backgroundColor: this.options.alignColor,\n }}\n />\n </div>\n );\n });\n }\n\n private calcEdgeLines(event: SnapEvent): SnapRenderLine[] {\n const { alignRects, snapRect, snapEdgeLines } = event;\n const edgeLines: SnapRenderLine[] = [];\n\n const topFullAlign = this.directionFullAlign({\n alignRects: alignRects.top,\n targetRect: snapRect,\n isVertical: true,\n });\n const bottomFullAlign = this.directionFullAlign({\n alignRects: alignRects.bottom,\n targetRect: snapRect,\n isVertical: true,\n });\n const leftFullAlign = this.directionFullAlign({\n alignRects: alignRects.left,\n targetRect: snapRect,\n isVertical: false,\n });\n const rightFullAlign = this.directionFullAlign({\n alignRects: alignRects.right,\n targetRect: snapRect,\n isVertical: false,\n });\n\n // 处理顶部对齐\n if (topFullAlign) {\n const top = topFullAlign.rect.top;\n const height = bottomFullAlign\n ? snapRect.bottom - snapRect.height / 2 - top\n : snapRect.bottom - top;\n const width = this.options.edgeLineWidth;\n const lineData = {\n top,\n width,\n height,\n };\n edgeLines.push({\n className: 'edge-full-top-left',\n sourceNode: topFullAlign.sourceNodeId,\n left: snapRect.left,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-top-right',\n sourceNode: topFullAlign.sourceNodeId,\n left: snapRect.right,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-top-mid',\n sourceNode: topFullAlign.sourceNodeId,\n left: snapRect.left + snapRect.width / 2,\n dashed: true,\n ...lineData,\n });\n }\n\n // 处理底部对齐\n if (bottomFullAlign) {\n const top = topFullAlign ? snapRect.top + snapRect.height / 2 : snapRect.top;\n const height = bottomFullAlign.rect.bottom - top;\n const width = this.options.edgeLineWidth;\n const lineData = {\n top,\n width,\n height,\n };\n edgeLines.push({\n className: 'edge-full-bottom-left',\n sourceNode: bottomFullAlign.sourceNodeId,\n left: snapRect.left,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-bottom-right',\n sourceNode: bottomFullAlign.sourceNodeId,\n left: snapRect.right,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-bottom-mid',\n sourceNode: bottomFullAlign.sourceNodeId,\n left: snapRect.left + snapRect.width / 2,\n dashed: true,\n ...lineData,\n });\n }\n\n // 处理左侧对齐\n if (leftFullAlign) {\n const left = leftFullAlign.rect.left;\n const width = rightFullAlign\n ? snapRect.right - snapRect.width / 2 - left\n : snapRect.right - left;\n const height = this.options.edgeLineWidth;\n const lineData = {\n left,\n width,\n height,\n };\n edgeLines.push({\n className: 'edge-full-left-top',\n sourceNode: leftFullAlign.sourceNodeId,\n top: snapRect.top,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-left-bottom',\n sourceNode: leftFullAlign.sourceNodeId,\n top: snapRect.bottom,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-left-mid',\n sourceNode: leftFullAlign.sourceNodeId,\n top: snapRect.top + snapRect.height / 2,\n dashed: true,\n ...lineData,\n });\n }\n\n // 处理右侧对齐\n if (rightFullAlign) {\n const left = leftFullAlign ? snapRect.left + snapRect.width / 2 : snapRect.left;\n const width = rightFullAlign.rect.right - left;\n const height = this.options.edgeLineWidth;\n const lineData = {\n left,\n width,\n height,\n };\n edgeLines.push({\n className: 'edge-full-right-top',\n sourceNode: rightFullAlign.sourceNodeId,\n top: snapRect.top,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-right-bottom',\n sourceNode: rightFullAlign.sourceNodeId,\n top: snapRect.bottom,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-right-mid',\n sourceNode: rightFullAlign.sourceNodeId,\n top: snapRect.top + snapRect.height / 2,\n dashed: true,\n ...lineData,\n });\n }\n\n const snappedEdgeLines = Object.entries(snapEdgeLines)\n .map(([direction, snapLine]) => {\n if (!snapLine) {\n return;\n }\n const sourceNode = this.document.getNode(snapLine.sourceNodeId);\n if (!sourceNode) {\n return;\n }\n const nodeRect = sourceNode.getData(FlowNodeTransformData).bounds;\n if (isNumber(snapLine.x)) {\n // 垂直\n const top = Math.min(nodeRect.top, snapRect.top);\n const bottom = Math.max(nodeRect.bottom, snapRect.bottom);\n const height = bottom - top;\n const left = snapLine.x;\n const width = this.options.edgeLineWidth;\n const isMidX = direction === 'midVertical';\n const lineData: SnapRenderLine = {\n className: `edge-snapped-${direction}`,\n sourceNode: snapLine.sourceNodeId,\n top,\n left,\n width,\n height,\n dashed: isMidX,\n };\n const onTop = top === nodeRect.top;\n if (onTop && topFullAlign) {\n return;\n }\n if (!onTop && bottomFullAlign) {\n return;\n }\n return lineData;\n } else if (isNumber(snapLine.y)) {\n // 水平\n const left = Math.min(nodeRect.left, snapRect.left);\n const right = Math.max(nodeRect.right, snapRect.right);\n const width = right - left;\n const top = snapLine.y;\n const height = this.options.edgeLineWidth;\n const isMidY = direction === 'midHorizontal';\n const lineData: SnapRenderLine = {\n className: `edge-snapped-${direction}`,\n sourceNode: snapLine.sourceNodeId,\n top,\n left,\n width,\n height,\n dashed: isMidY,\n };\n const onLeft = left === nodeRect.left;\n if (onLeft && leftFullAlign) {\n return;\n }\n if (!onLeft && rightFullAlign) {\n return;\n }\n return lineData;\n }\n })\n .filter(Boolean) as SnapRenderLine[];\n\n edgeLines.push(...snappedEdgeLines);\n\n return edgeLines;\n }\n\n private directionFullAlign(params: {\n alignRects: AlignRect[];\n targetRect: Rectangle;\n isVertical: boolean;\n }): AlignRect | undefined {\n const { alignRects, targetRect, isVertical } = params;\n let fullAlignIndex = -1;\n for (let i = 0; i < alignRects.length; i++) {\n const alignRect = alignRects[i];\n const prevRect = alignRects[i - 1]?.rect ?? targetRect;\n const isFullAlign = this.rectFullAlign(alignRect.rect, prevRect, isVertical);\n if (!isFullAlign) {\n // 未对齐则中断\n break; // 用 for 循环 + break 反而比 Array.findIndex 实现可读性更好\n }\n fullAlignIndex = i;\n }\n const fullAlignRect = alignRects[fullAlignIndex];\n return fullAlignRect;\n }\n\n private rectFullAlign(rectA: Rectangle, rectB: Rectangle, isVertical: boolean): boolean {\n if (isVertical) {\n return isEqual(rectA.left, rectB.left) && isEqual(rectA.right, rectB.right);\n } else {\n return isEqual(rectA.top, rectB.top) && isEqual(rectA.bottom, rectB.bottom);\n }\n }\n\n private calcAlignLines(event: SnapEvent): SnapRenderLine[] {\n const { alignRects, alignSpacing, snapRect } = event;\n\n const topAlignLines = this.calcDirectionAlignLines({\n alignRects: alignRects.top,\n targetRect: snapRect,\n isVertical: true,\n spacing: alignSpacing.midVertical ?? alignSpacing.top,\n });\n\n const bottomAlignLines = this.calcDirectionAlignLines({\n alignRects: alignRects.bottom,\n targetRect: snapRect,\n isVertical: true,\n spacing: alignSpacing.midVertical ?? alignSpacing.bottom,\n });\n\n const leftAlignLines = this.calcDirectionAlignLines({\n alignRects: alignRects.left,\n targetRect: snapRect,\n isVertical: false,\n spacing: alignSpacing.midHorizontal ?? alignSpacing.left,\n });\n\n const rightAlignLines = this.calcDirectionAlignLines({\n alignRects: alignRects.right,\n targetRect: snapRect,\n isVertical: false,\n spacing: alignSpacing.midHorizontal ?? alignSpacing.right,\n });\n\n return [...topAlignLines, ...bottomAlignLines, ...leftAlignLines, ...rightAlignLines];\n }\n\n private calcDirectionAlignLines(params: {\n alignRects: AlignRect[];\n targetRect: Rectangle;\n isVertical: boolean;\n spacing?: number;\n }) {\n const { alignRects, targetRect, isVertical, spacing } = params;\n const alignLines: SnapRenderLine[] = [];\n if (!spacing) {\n return alignLines;\n }\n for (let i = 0; i < alignRects.length; i++) {\n const alignRect = alignRects[i];\n const rect = alignRect.rect;\n const prevRect = alignRects[i - 1]?.rect ?? targetRect;\n\n const betweenSpacing = isVertical\n ? Math.min(Math.abs(prevRect.top - rect.bottom), Math.abs(prevRect.bottom - rect.top))\n : Math.min(Math.abs(prevRect.left - rect.right), Math.abs(prevRect.right - rect.left));\n if (!isEqual(betweenSpacing, spacing)) {\n // 不连续,需要中断\n break; // 因为要用到 break,所以不能用 Array.map()\n }\n if (isVertical) {\n const centerX = this.calcHorizontalIntersectionCenter(rect, targetRect);\n alignLines.push({\n className: 'align-vertical',\n sourceNode: alignRect.sourceNodeId,\n top: Math.min(rect.bottom, prevRect.bottom),\n left: centerX,\n width: 1,\n height: spacing,\n });\n } else {\n const centerY = this.calcVerticalIntersectionCenter(rect, targetRect);\n alignLines.push({\n className: 'align-horizontal',\n sourceNode: alignRect.sourceNodeId,\n top: centerY,\n left: Math.min(rect.right, prevRect.right),\n width: spacing,\n height: 1,\n });\n }\n }\n return alignLines;\n }\n\n private calcVerticalIntersectionCenter(rectA: Rectangle, rectB: Rectangle): number {\n const top = Math.max(rectA.top, rectB.top);\n const bottom = Math.min(rectA.bottom, rectB.bottom);\n return (top + bottom) / 2;\n }\n\n private calcHorizontalIntersectionCenter(rectA: Rectangle, rectB: Rectangle): number {\n const left = Math.max(rectA.left, rectB.left);\n const right = Math.min(rectA.right, rectB.right);\n return (left + right) / 2;\n }\n}\n"],"mappings":"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","names":["import_core","import_free_layout_core","import_document","import_inversify","import_utils","import_free_layout_core","import_document","import_core","React"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/create-plugin.ts","../src/service.ts","../src/constant.ts","../src/utils.ts","../src/layer.tsx"],"sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport { createFreeSnapPlugin } from './create-plugin';\nexport { WorkflowSnapService } from './service';\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { definePluginCreator } from '@flowgram.ai/core';\n\nimport {\n FreeSnapPluginOptions,\n WorkflowSnapLayerOptions,\n WorkflowSnapServiceOptions,\n} from './type';\nimport { WorkflowSnapService } from './service';\nimport { WorkflowSnapLayer } from './layer';\nimport { SnapDefaultOptions } from './constant';\n\nexport const createFreeSnapPlugin = definePluginCreator<FreeSnapPluginOptions>({\n onBind({ bind }) {\n bind(WorkflowSnapService).toSelf().inSingletonScope();\n },\n onInit(ctx, opts) {\n const options: WorkflowSnapServiceOptions & WorkflowSnapLayerOptions = {\n ...SnapDefaultOptions,\n ...opts,\n };\n ctx.playground.registerLayer(WorkflowSnapLayer, options);\n const snapService = ctx.get<WorkflowSnapService>(WorkflowSnapService);\n snapService.init(options);\n },\n onDispose(ctx) {\n const snapService = ctx.get<WorkflowSnapService>(WorkflowSnapService);\n snapService.dispose();\n },\n});\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { inject, injectable } from 'inversify';\nimport { Disposable, Emitter, Rectangle } from '@flowgram.ai/utils';\nimport { IPoint } from '@flowgram.ai/utils';\nimport { WorkflowNodeEntity, WorkflowDocument } from '@flowgram.ai/free-layout-core';\nimport { WorkflowDragService } from '@flowgram.ai/free-layout-core';\nimport { FlowNodeTransformData } from '@flowgram.ai/document';\nimport { FlowNodeBaseType } from '@flowgram.ai/document';\nimport { EntityManager, PlaygroundConfigEntity, TransformData } from '@flowgram.ai/core';\n\nimport { isEqual, isGreaterThan, isLessThan, isLessThanOrEqual, isNumber } from './utils';\nimport type {\n SnapEvent,\n SnapHorizontalLine,\n SnapLines,\n SnapMidHorizontalLine,\n SnapMidVerticalLine,\n SnapVerticalLine,\n WorkflowSnapServiceOptions,\n AlignRects,\n AlignRect,\n AlignSpacing,\n SnapNodeRect,\n SnapEdgeLines,\n} from './type';\nimport { SnapDefaultOptions } from './constant';\n\n@injectable()\nexport class WorkflowSnapService {\n @inject(WorkflowDocument) private readonly document: WorkflowDocument;\n\n @inject(EntityManager) private readonly entityManager: EntityManager;\n\n @inject(WorkflowDragService)\n private readonly dragService: WorkflowDragService;\n\n @inject(PlaygroundConfigEntity)\n private readonly playgroundConfig: PlaygroundConfigEntity;\n\n private disposers: Disposable[] = [];\n\n private options: WorkflowSnapServiceOptions;\n\n private snapEmitter = new Emitter<SnapEvent>();\n\n public readonly onSnap = this.snapEmitter.event;\n\n private _disabled = false;\n\n public init(params: Partial<WorkflowSnapServiceOptions> = {}): void {\n this.options = {\n ...SnapDefaultOptions,\n ...params,\n };\n this.mountListener();\n }\n\n public dispose(): void {\n this.disposers.forEach((disposer) => disposer.dispose());\n }\n\n public get disabled(): boolean {\n return this._disabled;\n }\n\n public disable(): void {\n if (this._disabled) {\n return;\n }\n this._disabled = true;\n this.clear();\n }\n\n public enable(): void {\n if (!this._disabled) {\n return;\n }\n this._disabled = false;\n this.clear();\n }\n\n private mountListener(): void {\n const dragAdjusterDisposer = this.dragService.registerPosAdjuster((params) => {\n const { selectedNodes: targetNodes, position } = params;\n const isMultiSnapping = this.options.enableMultiSnapping ? false : targetNodes.length !== 1;\n if (this._disabled || !this.options.enableEdgeSnapping || isMultiSnapping) {\n return {\n x: 0,\n y: 0,\n };\n }\n return this.snapping({\n targetNodes,\n position,\n });\n });\n const dragEndDisposer = this.dragService.onNodesDrag((event) => {\n if (event.type !== 'onDragEnd' || this._disabled) {\n return;\n }\n if (this.options.enableGridSnapping) {\n this.gridSnapping({\n targetNodes: event.nodes,\n gridSize: this.options.gridSize,\n });\n }\n if (this.options.enableEdgeSnapping) {\n this.clear();\n }\n });\n this.disposers.push(dragAdjusterDisposer, dragEndDisposer);\n }\n\n private snapping(params: { targetNodes: WorkflowNodeEntity[]; position: IPoint }): IPoint {\n const { targetNodes, position } = params;\n\n const targetBounds = this.getBounds(targetNodes);\n\n const targetRect = new Rectangle(\n position.x,\n position.y,\n targetBounds.width,\n targetBounds.height\n );\n\n const snapNodeRects = this.getSnapNodeRects({\n targetNodes,\n targetRect,\n });\n\n const { alignOffset, alignRects, alignSpacing } = this.calcAlignOffset({\n targetRect,\n alignThreshold: this.options.edgeThreshold,\n snapNodeRects,\n });\n\n const { snapOffset, snapEdgeLines } = this.calcSnapOffset({\n targetRect,\n edgeThreshold: this.options.edgeThreshold,\n snapNodeRects,\n });\n\n const offset: IPoint = {\n x: snapOffset.x || alignOffset.x,\n y: snapOffset.y || alignOffset.y,\n };\n\n const snapRect = new Rectangle(\n position.x + offset.x,\n position.y + offset.y,\n targetRect.width,\n targetRect.height\n );\n\n this.snapEmitter.fire({\n snapRect,\n snapEdgeLines,\n alignRects,\n alignSpacing,\n });\n\n return offset;\n }\n\n private calcSnapOffset(params: {\n snapNodeRects: SnapNodeRect[];\n targetRect: Rectangle;\n edgeThreshold: number;\n }): {\n snapOffset: IPoint;\n snapEdgeLines: SnapEdgeLines;\n } {\n const { snapNodeRects, edgeThreshold, targetRect } = params;\n\n const snapLines = this.getSnapLines({\n snapNodeRects,\n });\n\n // 找到最近的线条\n const topYClosestLine = snapLines.horizontal.find((line) =>\n isLessThanOrEqual(Math.abs(line.y - targetRect.top), edgeThreshold)\n );\n const bottomYClosestLine = snapLines.horizontal.find((line) =>\n isLessThanOrEqual(Math.abs(line.y - targetRect.bottom), edgeThreshold)\n );\n const leftXClosestLine = snapLines.vertical.find((line) =>\n isLessThanOrEqual(Math.abs(line.x - targetRect.left), edgeThreshold)\n );\n const rightXClosestLine = snapLines.vertical.find((line) =>\n isLessThanOrEqual(Math.abs(line.x - targetRect.right), edgeThreshold)\n );\n const midYClosestLine = snapLines.midHorizontal.find((line) =>\n isLessThanOrEqual(Math.abs(line.y - targetRect.center.y), edgeThreshold)\n );\n const midXClosestLine = snapLines.midVertical.find((line) =>\n isLessThanOrEqual(Math.abs(line.x - targetRect.center.x), edgeThreshold)\n );\n\n // 计算最近坐标\n const topYClosest = topYClosestLine?.y;\n const bottomYClosest = isNumber(bottomYClosestLine?.y)\n ? bottomYClosestLine!.y - targetRect.height\n : undefined;\n const leftXClosest = leftXClosestLine?.x;\n const rightXClosest = isNumber(rightXClosestLine?.x)\n ? rightXClosestLine!.x - targetRect.width\n : undefined;\n const midYClosest = isNumber(midYClosestLine?.y)\n ? midYClosestLine!.y - targetRect.height / 2\n : undefined;\n const midXClosest = isNumber(midXClosestLine?.x)\n ? midXClosestLine!.x - targetRect.width / 2\n : undefined;\n\n // 吸附后坐标,按优先级取值\n const snappingPosition = {\n x: midXClosest ?? leftXClosest ?? rightXClosest ?? targetRect.x,\n y: midYClosest ?? topYClosest ?? bottomYClosest ?? targetRect.y,\n };\n\n // 吸附修正偏移量\n const snapOffset: IPoint = {\n x: snappingPosition.x - targetRect.x,\n y: snappingPosition.y - targetRect.y,\n };\n\n // 生效的吸附线条\n const snapEdgeLines: SnapEdgeLines = {\n top: isEqual(topYClosest, snappingPosition.y) ? topYClosestLine : undefined,\n bottom: isEqual(bottomYClosest, snappingPosition.y) ? bottomYClosestLine : undefined,\n left: isEqual(leftXClosest, snappingPosition.x) ? leftXClosestLine : undefined,\n right: isEqual(rightXClosest, snappingPosition.x) ? rightXClosestLine : undefined,\n midVertical: isEqual(midXClosest, snappingPosition.x) ? midXClosestLine : undefined,\n midHorizontal: isEqual(midYClosest, snappingPosition.y) ? midYClosestLine : undefined,\n };\n\n return { snapOffset, snapEdgeLines };\n }\n\n private gridSnapping(params: { gridSize: number; targetNodes: WorkflowNodeEntity[] }): void {\n const { gridSize, targetNodes } = params;\n const rect = this.getBounds(targetNodes);\n const snap = (value: number) => Math.round(value / gridSize) * gridSize;\n const snappedPosition: IPoint = {\n x: snap(rect.x),\n y: snap(rect.y),\n };\n const offset: IPoint = {\n x: snappedPosition.x - rect.x,\n y: snappedPosition.y - rect.y,\n };\n targetNodes.forEach((node) =>\n this.updateNodePositionWithOffset({\n node,\n offset,\n })\n );\n }\n\n private clear() {\n this.snapEmitter.fire({\n snapEdgeLines: {},\n snapRect: Rectangle.EMPTY,\n alignRects: {\n top: [],\n bottom: [],\n left: [],\n right: [],\n },\n alignSpacing: {},\n });\n }\n\n private getSnapLines(params: { snapNodeRects: SnapNodeRect[] }): SnapLines {\n const { snapNodeRects } = params;\n const horizontalLines: SnapHorizontalLine[] = [];\n const verticalLines: SnapVerticalLine[] = [];\n const midHorizontalLines: SnapMidHorizontalLine[] = [];\n const midVerticalLines: SnapMidVerticalLine[] = [];\n\n snapNodeRects.forEach((snapNodeRect) => {\n const nodeBounds = snapNodeRect.rect;\n const nodeCenter = nodeBounds.center;\n // 边缘横线\n const top: SnapHorizontalLine = {\n y: nodeBounds.top,\n sourceNodeId: snapNodeRect.id,\n };\n const bottom: SnapHorizontalLine = {\n y: nodeBounds.bottom,\n sourceNodeId: snapNodeRect.id,\n };\n // 边缘竖线\n const left: SnapVerticalLine = {\n x: nodeBounds.left,\n sourceNodeId: snapNodeRect.id,\n };\n const right: SnapVerticalLine = {\n x: nodeBounds.right,\n sourceNodeId: snapNodeRect.id,\n };\n // 中间横线\n const midHorizontal: SnapMidHorizontalLine = {\n y: nodeCenter.y,\n sourceNodeId: snapNodeRect.id,\n };\n // 中间竖线\n const midVertical: SnapMidVerticalLine = {\n x: nodeCenter.x,\n sourceNodeId: snapNodeRect.id,\n };\n horizontalLines.push(top, bottom);\n verticalLines.push(left, right);\n midHorizontalLines.push(midHorizontal);\n midVerticalLines.push(midVertical);\n });\n\n return {\n horizontal: horizontalLines,\n vertical: verticalLines,\n midHorizontal: midHorizontalLines,\n midVertical: midVerticalLines,\n };\n }\n\n private getAvailableNodes(params: {\n targetNodes: WorkflowNodeEntity[];\n targetRect: Rectangle;\n }): WorkflowNodeEntity[] {\n const { targetNodes, targetRect } = params;\n\n const targetCenter = targetRect.center;\n const targetContainerId = targetNodes[0].parent?.id ?? this.document.root.id;\n\n const disabledNodeIds = targetNodes.map((n) => n.id);\n disabledNodeIds.push(FlowNodeBaseType.ROOT);\n const availableNodes = this.nodes\n .filter((n) => n.parent?.id === targetContainerId)\n .filter((n) => !disabledNodeIds.includes(n.id))\n .sort((nodeA, nodeB) => {\n const nodeCenterA = nodeA.getData(FlowNodeTransformData)!.bounds.center;\n const nodeCenterB = nodeB.getData(FlowNodeTransformData)!.bounds.center;\n // 距离越近优先级越高\n const distanceA =\n Math.abs(nodeCenterA.x - targetCenter.x) + Math.abs(nodeCenterA.y - targetCenter.y);\n const distanceB =\n Math.abs(nodeCenterB.x - targetCenter.x) + Math.abs(nodeCenterB.y - targetCenter.y);\n return distanceA - distanceB;\n });\n return availableNodes;\n }\n\n private viewRect(): Rectangle {\n const { width, height, scrollX, scrollY, zoom } = this.playgroundConfig.config;\n return new Rectangle(scrollX / zoom, scrollY / zoom, width / zoom, height / zoom);\n }\n\n private getSnapNodeRects(params: {\n targetNodes: WorkflowNodeEntity[];\n targetRect: Rectangle;\n }): SnapNodeRect[] {\n const availableNodes = this.getAvailableNodes(params);\n const viewRect = this.viewRect();\n return availableNodes\n .map((node) => {\n const snapNodeRect: SnapNodeRect = {\n id: node.id,\n rect: node.getData(FlowNodeTransformData).bounds,\n entity: node,\n };\n if (\n this.options.enableOnlyViewportSnapping &&\n node.parent?.flowNodeType === FlowNodeBaseType.ROOT &&\n !Rectangle.intersects(viewRect, snapNodeRect.rect)\n ) {\n // 最外层节点仅包含当前可见节点\n return;\n }\n return snapNodeRect;\n })\n .filter(Boolean) as SnapNodeRect[];\n }\n\n private get nodes(): WorkflowNodeEntity[] {\n return this.entityManager.getEntities<WorkflowNodeEntity>(WorkflowNodeEntity);\n }\n\n private getBounds(nodes: WorkflowNodeEntity[]): Rectangle {\n if (nodes.length === 0) {\n return Rectangle.EMPTY;\n }\n return Rectangle.enlarge(nodes.map((n) => n.getData(FlowNodeTransformData)!.bounds));\n }\n\n private updateNodePositionWithOffset(params: { node: WorkflowNodeEntity; offset: IPoint }): void {\n const { node, offset } = params;\n const transform = node.getData(TransformData);\n const positionWithOffset: IPoint = {\n x: transform.position.x + offset.x,\n y: transform.position.y + offset.y,\n };\n transform.update({\n position: positionWithOffset,\n });\n this.document.layout.updateAffectedTransform(node);\n }\n\n private calcAlignOffset(params: {\n snapNodeRects: SnapNodeRect[];\n targetRect: Rectangle;\n alignThreshold: number;\n }): {\n alignOffset: IPoint;\n alignRects: AlignRects;\n alignSpacing: AlignSpacing;\n } {\n const { snapNodeRects, targetRect, alignThreshold } = params;\n\n const alignRects = this.getAlignRects({\n targetRect,\n snapNodeRects,\n });\n\n const alignSpacing = this.calcAlignSpacing({\n targetRect,\n alignRects,\n });\n\n let topY: number | undefined;\n let bottomY: number | undefined;\n let leftX: number | undefined;\n let rightX: number | undefined;\n let midY: number | undefined;\n let midX: number | undefined;\n\n if (alignSpacing.top) {\n const topAlignY = alignRects.top[0].rect.bottom + alignSpacing.top;\n const isAlignTop = isLessThanOrEqual(Math.abs(targetRect.top - topAlignY), alignThreshold);\n if (isAlignTop) {\n // 生效\n topY = topAlignY;\n } else {\n // 失效\n alignSpacing.top = undefined;\n }\n }\n if (alignSpacing.bottom) {\n const bottomAlignY = alignRects.bottom[0].rect.top - alignSpacing.bottom;\n const isAlignBottom = isLessThan(Math.abs(targetRect.bottom - bottomAlignY), alignThreshold);\n if (isAlignBottom) {\n bottomY = bottomAlignY - targetRect.height;\n } else {\n alignSpacing.bottom = undefined;\n }\n }\n if (alignSpacing.left) {\n const leftAlignX = alignRects.left[0].rect.right + alignSpacing.left;\n const isAlignLeft = isLessThanOrEqual(Math.abs(targetRect.left - leftAlignX), alignThreshold);\n if (isAlignLeft) {\n leftX = leftAlignX;\n } else {\n alignSpacing.left = undefined;\n }\n }\n if (alignSpacing.right) {\n const rightAlignX = alignRects.right[0].rect.left - alignSpacing.right;\n const isAlignRight = isLessThanOrEqual(\n Math.abs(targetRect.right - rightAlignX),\n alignThreshold\n );\n if (isAlignRight) {\n rightX = rightAlignX - targetRect.width;\n } else {\n alignSpacing.right = undefined;\n }\n }\n if (alignSpacing.midHorizontal) {\n const leftAlignX = alignRects.left[0].rect.right + alignSpacing.midHorizontal;\n const isAlignMidHorizontal = isLessThanOrEqual(\n Math.abs(targetRect.left - leftAlignX),\n alignThreshold\n );\n if (isAlignMidHorizontal) {\n midX = leftAlignX;\n } else {\n alignSpacing.midHorizontal = undefined;\n }\n }\n if (alignSpacing.midVertical) {\n const topAlignY = alignRects.top[0].rect.bottom + alignSpacing.midVertical;\n const isAlignMidVertical = isLessThanOrEqual(\n Math.abs(targetRect.top - topAlignY),\n alignThreshold\n );\n if (isAlignMidVertical) {\n midY = topAlignY;\n } else {\n alignSpacing.midVertical = undefined;\n }\n }\n\n const alignPosition: IPoint = {\n x: midX ?? leftX ?? rightX ?? targetRect.x,\n y: midY ?? topY ?? bottomY ?? targetRect.y,\n };\n\n const alignOffset: IPoint = {\n x: alignPosition.x - targetRect.x,\n y: alignPosition.y - targetRect.y,\n };\n\n return { alignOffset, alignRects, alignSpacing };\n }\n\n private calcAlignSpacing(params: {\n targetRect: Rectangle;\n alignRects: AlignRects;\n }): AlignSpacing {\n const { targetRect, alignRects } = params;\n\n const topSpacing = this.getDirectionAlignSpacing({\n rects: alignRects.top,\n isHorizontal: false,\n });\n const bottomSpacing = this.getDirectionAlignSpacing({\n rects: alignRects.bottom,\n isHorizontal: false,\n });\n const leftSpacing = this.getDirectionAlignSpacing({\n rects: alignRects.left,\n isHorizontal: true,\n });\n const rightSpacing = this.getDirectionAlignSpacing({\n rects: alignRects.right,\n isHorizontal: true,\n });\n const midHorizontalSpacing = this.getMidAlignSpacing({\n rectA: alignRects.left[0]?.rect,\n rectB: alignRects.right[0]?.rect,\n targetRect,\n isHorizontal: true,\n });\n const midVerticalSpacing = this.getMidAlignSpacing({\n rectA: alignRects.top[0]?.rect,\n rectB: alignRects.bottom[0]?.rect,\n targetRect,\n isHorizontal: false,\n });\n return {\n top: topSpacing,\n bottom: bottomSpacing,\n left: leftSpacing,\n right: rightSpacing,\n midHorizontal: midHorizontalSpacing,\n midVertical: midVerticalSpacing,\n };\n }\n\n private getAlignRects(params: {\n targetRect: Rectangle;\n snapNodeRects: SnapNodeRect[];\n }): AlignRects {\n const { targetRect, snapNodeRects } = params;\n\n const topVerticalRects: AlignRect[] = [];\n const bottomVerticalRects: AlignRect[] = [];\n const leftHorizontalRects: AlignRect[] = [];\n const rightHorizontalRects: AlignRect[] = [];\n\n snapNodeRects.forEach((snapNodeRect) => {\n const nodeRect = snapNodeRect.rect;\n const { isVerticalIntersection, isHorizontalIntersection, isIntersection } =\n this.intersection(nodeRect, targetRect);\n if (isIntersection) {\n // 忽略重叠的节点\n return;\n } else if (isVerticalIntersection) {\n // 垂直重合\n if (isGreaterThan(nodeRect.center.y, targetRect.center.y)) {\n // 下方\n bottomVerticalRects.push({\n rect: nodeRect,\n sourceNodeId: snapNodeRect.id,\n });\n } else {\n // 上方\n topVerticalRects.push({\n rect: nodeRect,\n sourceNodeId: snapNodeRect.id,\n });\n }\n } else if (isHorizontalIntersection) {\n // 水平重合\n if (isGreaterThan(nodeRect.center.x, targetRect.center.x)) {\n // 右方\n rightHorizontalRects.push({\n rect: nodeRect,\n sourceNodeId: snapNodeRect.id,\n });\n } else {\n // 左方\n leftHorizontalRects.push({\n rect: nodeRect,\n sourceNodeId: snapNodeRect.id,\n });\n }\n }\n });\n\n return {\n top: topVerticalRects,\n bottom: bottomVerticalRects,\n left: leftHorizontalRects,\n right: rightHorizontalRects,\n };\n }\n\n private getMidAlignSpacing(params: {\n rectA?: Rectangle;\n rectB?: Rectangle;\n targetRect: Rectangle;\n isHorizontal: boolean;\n }): number | undefined {\n const { rectA, rectB, targetRect, isHorizontal } = params;\n if (!rectA || !rectB) {\n return;\n }\n const { isVerticalIntersection, isHorizontalIntersection, isIntersection } = this.intersection(\n rectA,\n rectB\n );\n if (isIntersection) {\n return;\n }\n if (isHorizontal && isHorizontalIntersection && !isVerticalIntersection) {\n const betweenSpacing = Math.min(\n Math.abs(rectA.left - rectB.right),\n Math.abs(rectA.right - rectB.left)\n );\n return (betweenSpacing - targetRect.width) / 2;\n } else if (!isHorizontal && isVerticalIntersection && !isHorizontalIntersection) {\n const betweenSpacing = Math.min(\n Math.abs(rectA.top - rectB.bottom),\n Math.abs(rectA.bottom - rectB.top)\n );\n return (betweenSpacing - targetRect.height) / 2;\n }\n }\n\n private getDirectionAlignSpacing(params: {\n rects: AlignRect[];\n isHorizontal: boolean;\n }): number | undefined {\n const { rects, isHorizontal } = params;\n if (rects.length < 2) {\n // 非法情况\n return;\n }\n const rectA = rects[0].rect;\n const rectB = rects[1].rect;\n\n const { isVerticalIntersection, isHorizontalIntersection, isIntersection } = this.intersection(\n rectA,\n rectB\n );\n\n if (isIntersection) {\n // 非法情况:重叠\n return;\n }\n if (isHorizontal && isHorizontalIntersection && !isVerticalIntersection) {\n return Math.min(Math.abs(rectA.left - rectB.right), Math.abs(rectA.right - rectB.left));\n } else if (!isHorizontal && isVerticalIntersection && !isHorizontalIntersection) {\n return Math.min(Math.abs(rectA.top - rectB.bottom), Math.abs(rectA.bottom - rectB.top));\n }\n return;\n }\n\n private intersection(\n rectA: Rectangle,\n rectB: Rectangle\n ): {\n isHorizontalIntersection: boolean;\n isVerticalIntersection: boolean;\n isIntersection: boolean;\n } {\n const isVerticalIntersection =\n isLessThan(rectA.left, rectB.right) && isGreaterThan(rectA.right, rectB.left);\n const isHorizontalIntersection =\n isLessThan(rectA.top, rectB.bottom) && isGreaterThan(rectA.bottom, rectB.top);\n const isIntersection = isHorizontalIntersection && isVerticalIntersection;\n\n return {\n isHorizontalIntersection,\n isVerticalIntersection,\n isIntersection,\n };\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport type { WorkflowSnapLayerOptions, WorkflowSnapServiceOptions } from './type';\n\nexport const SnapDefaultOptions: WorkflowSnapServiceOptions & WorkflowSnapLayerOptions = {\n enableEdgeSnapping: true,\n edgeThreshold: 7,\n enableGridSnapping: false,\n gridSize: 20,\n enableMultiSnapping: true,\n enableOnlyViewportSnapping: true,\n edgeColor: '#4E40E5',\n alignColor: '#4E40E5',\n edgeLineWidth: 2,\n alignLineWidth: 2,\n alignCrossWidth: 16,\n};\n\nexport const Epsilon = 0.00001;\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { Epsilon } from './constant';\n\n/** 检查浮点数 a 是否等于 b */\nexport const isEqual = (a: number | undefined, b: number | undefined): boolean => {\n if (a === undefined || b === undefined) {\n return false;\n }\n // 检查 a 和 b 的差的绝对值是否小于 Epsilon\n return Math.abs(a - b) < Epsilon;\n};\n\n/** 检查浮点数 a 是否小于 b */\nexport const isLessThan = (a: number | undefined, b: number | undefined): boolean => {\n if (a === undefined || b === undefined) {\n return false;\n }\n // 检查 a 是否显著小于 b\n return b - a > Epsilon;\n};\n\n/** 检查浮点数 a 是否大于 b */\nexport const isGreaterThan = (a: number | undefined, b: number | undefined): boolean => {\n if (a === undefined || b === undefined) {\n return false;\n }\n return a - b > Epsilon;\n};\n\n/** 检查浮点数 a 是否小于等于 b */\nexport const isLessThanOrEqual = (a: number | undefined, b: number | undefined): boolean =>\n isEqual(a, b) || isLessThan(a, b);\n\n/** 检查浮点数 a 是否大于等于 b */\nexport const isGreaterThanOrEqual = (a: number | undefined, b: number | undefined): boolean =>\n isEqual(a, b) || isGreaterThan(a, b);\n\n/** 检查值是否是数字类型 */\nexport const isNumber = (value: unknown): value is number =>\n typeof value === 'number' && !isNaN(value);\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React from 'react';\n\nimport { inject, injectable } from 'inversify';\nimport { domUtils } from '@flowgram.ai/utils';\nimport { Rectangle } from '@flowgram.ai/utils';\nimport { WorkflowDocument } from '@flowgram.ai/free-layout-core';\nimport { FlowNodeTransformData } from '@flowgram.ai/document';\nimport { Layer } from '@flowgram.ai/core';\n\nimport { isEqual, isGreaterThan, isNumber } from './utils';\nimport { AlignRect, SnapEvent, WorkflowSnapLayerOptions } from './type';\nimport { WorkflowSnapService } from './service';\n\ninterface SnapRenderLine {\n className: string;\n sourceNode: string;\n top: number;\n left: number;\n width: number;\n height: number;\n dashed?: boolean;\n}\n\n@injectable()\nexport class WorkflowSnapLayer extends Layer<WorkflowSnapLayerOptions> {\n public static type = 'WorkflowSnapLayer';\n\n @inject(WorkflowDocument) private readonly document: WorkflowDocument;\n\n @inject(WorkflowSnapService) private readonly service: WorkflowSnapService;\n\n public readonly node = domUtils.createDivWithClass(\n 'gedit-playground-layer gedit-flow-snap-layer'\n );\n\n private edgeLines: SnapRenderLine[] = [];\n\n private alignLines: SnapRenderLine[] = [];\n\n public onReady(): void {\n this.node.style.zIndex = '9999';\n this.toDispose.pushAll([\n this.service.onSnap((event: SnapEvent) => {\n this.edgeLines = this.calcEdgeLines(event);\n this.alignLines = this.calcAlignLines(event);\n this.render();\n }),\n ]);\n }\n\n public render(): JSX.Element {\n return (\n <>\n {this.alignLines.length > 0 && (\n <div className=\"workflow-snap-align-lines\">{this.renderAlignLines()}</div>\n )}\n {this.edgeLines.length > 0 && (\n <div className=\"workflow-snap-edge-lines\">{this.renderEdgeLines()}</div>\n )}\n </>\n );\n }\n\n public onZoom(scale: number): void {\n this.node.style.transform = `scale(${scale})`;\n }\n\n private renderEdgeLines(): JSX.Element[] {\n return this.edgeLines.map((renderLine: SnapRenderLine) => {\n const { className, sourceNode, top, left, width, height, dashed } = renderLine;\n const id = `${className}-${sourceNode}-${top}-${left}-${width}-${height}`;\n const isHorizontal = width < height;\n const border = `${this.options.edgeLineWidth}px ${dashed ? 'dashed' : 'solid'} ${\n this.options.edgeColor\n }`;\n return (\n <div\n className={`workflow-snap-edge-line ${className}`}\n data-testid=\"sdk.workflow.canvas.snap.edgeLine\"\n data-snap-line-id={id}\n data-snap-line-source-node={sourceNode}\n key={id}\n style={{\n top,\n left,\n width,\n height,\n position: 'absolute',\n borderLeft: isHorizontal ? border : 'none',\n borderTop: !isHorizontal ? border : 'none',\n }}\n />\n );\n });\n }\n\n private renderAlignLines(): JSX.Element[] {\n return this.alignLines.map((renderLine: SnapRenderLine) => {\n const id = `${renderLine.className}-${renderLine.sourceNode}-${renderLine.top}-${renderLine.left}-${renderLine.width}-${renderLine.height}`;\n const isHorizontal = isGreaterThan(renderLine.width, renderLine.height);\n const alignLineWidth = this.options.alignLineWidth; // 整体线条粗细\n const alignCrossWidth = this.options.alignCrossWidth; // 工字形横线的长度\n\n // 调整渲染位置以保持居中\n const adjustedTop = isHorizontal ? renderLine.top - alignLineWidth / 2 : renderLine.top;\n const adjustedLeft = isHorizontal ? renderLine.left : renderLine.left - alignLineWidth / 2;\n\n return (\n <div\n className={`workflow-snap-align-line ${renderLine.className}`}\n data-testid=\"sdk.workflow.canvas.snap.alignLine\"\n data-snap-line-id={id}\n data-snap-line-source-node={renderLine.sourceNode}\n key={id}\n style={{\n position: 'absolute',\n }}\n >\n {/* 主线 */}\n <div\n style={{\n position: 'absolute',\n top: adjustedTop,\n left: adjustedLeft,\n width: isHorizontal ? renderLine.width : alignLineWidth,\n height: isHorizontal ? alignLineWidth : renderLine.height,\n backgroundColor: this.options.alignColor,\n }}\n />\n {/* 左端或上端横线 */}\n <div\n style={{\n position: 'absolute',\n top: isHorizontal\n ? adjustedTop - (alignCrossWidth - alignLineWidth) / 2\n : adjustedTop,\n left: isHorizontal\n ? adjustedLeft\n : adjustedLeft - (alignCrossWidth - alignLineWidth) / 2,\n width: isHorizontal ? alignLineWidth : alignCrossWidth,\n height: isHorizontal ? alignCrossWidth : alignLineWidth,\n backgroundColor: this.options.alignColor,\n }}\n />\n {/* 右端或下端横线 */}\n <div\n style={{\n position: 'absolute',\n top: isHorizontal\n ? adjustedTop - (alignCrossWidth - alignLineWidth) / 2\n : adjustedTop + renderLine.height - alignLineWidth,\n left: isHorizontal\n ? adjustedLeft + renderLine.width - alignLineWidth\n : adjustedLeft - (alignCrossWidth - alignLineWidth) / 2,\n width: isHorizontal ? alignLineWidth : alignCrossWidth,\n height: isHorizontal ? alignCrossWidth : alignLineWidth,\n backgroundColor: this.options.alignColor,\n }}\n />\n </div>\n );\n });\n }\n\n private calcEdgeLines(event: SnapEvent): SnapRenderLine[] {\n const { alignRects, snapRect, snapEdgeLines } = event;\n const edgeLines: SnapRenderLine[] = [];\n\n const topFullAlign = this.directionFullAlign({\n alignRects: alignRects.top,\n targetRect: snapRect,\n isVertical: true,\n });\n const bottomFullAlign = this.directionFullAlign({\n alignRects: alignRects.bottom,\n targetRect: snapRect,\n isVertical: true,\n });\n const leftFullAlign = this.directionFullAlign({\n alignRects: alignRects.left,\n targetRect: snapRect,\n isVertical: false,\n });\n const rightFullAlign = this.directionFullAlign({\n alignRects: alignRects.right,\n targetRect: snapRect,\n isVertical: false,\n });\n\n // 处理顶部对齐\n if (topFullAlign) {\n const top = topFullAlign.rect.top;\n const height = bottomFullAlign\n ? snapRect.bottom - snapRect.height / 2 - top\n : snapRect.bottom - top;\n const width = this.options.edgeLineWidth;\n const lineData = {\n top,\n width,\n height,\n };\n edgeLines.push({\n className: 'edge-full-top-left',\n sourceNode: topFullAlign.sourceNodeId,\n left: snapRect.left,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-top-right',\n sourceNode: topFullAlign.sourceNodeId,\n left: snapRect.right,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-top-mid',\n sourceNode: topFullAlign.sourceNodeId,\n left: snapRect.left + snapRect.width / 2,\n dashed: true,\n ...lineData,\n });\n }\n\n // 处理底部对齐\n if (bottomFullAlign) {\n const top = topFullAlign ? snapRect.top + snapRect.height / 2 : snapRect.top;\n const height = bottomFullAlign.rect.bottom - top;\n const width = this.options.edgeLineWidth;\n const lineData = {\n top,\n width,\n height,\n };\n edgeLines.push({\n className: 'edge-full-bottom-left',\n sourceNode: bottomFullAlign.sourceNodeId,\n left: snapRect.left,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-bottom-right',\n sourceNode: bottomFullAlign.sourceNodeId,\n left: snapRect.right,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-bottom-mid',\n sourceNode: bottomFullAlign.sourceNodeId,\n left: snapRect.left + snapRect.width / 2,\n dashed: true,\n ...lineData,\n });\n }\n\n // 处理左侧对齐\n if (leftFullAlign) {\n const left = leftFullAlign.rect.left;\n const width = rightFullAlign\n ? snapRect.right - snapRect.width / 2 - left\n : snapRect.right - left;\n const height = this.options.edgeLineWidth;\n const lineData = {\n left,\n width,\n height,\n };\n edgeLines.push({\n className: 'edge-full-left-top',\n sourceNode: leftFullAlign.sourceNodeId,\n top: snapRect.top,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-left-bottom',\n sourceNode: leftFullAlign.sourceNodeId,\n top: snapRect.bottom,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-left-mid',\n sourceNode: leftFullAlign.sourceNodeId,\n top: snapRect.top + snapRect.height / 2,\n dashed: true,\n ...lineData,\n });\n }\n\n // 处理右侧对齐\n if (rightFullAlign) {\n const left = leftFullAlign ? snapRect.left + snapRect.width / 2 : snapRect.left;\n const width = rightFullAlign.rect.right - left;\n const height = this.options.edgeLineWidth;\n const lineData = {\n left,\n width,\n height,\n };\n edgeLines.push({\n className: 'edge-full-right-top',\n sourceNode: rightFullAlign.sourceNodeId,\n top: snapRect.top,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-right-bottom',\n sourceNode: rightFullAlign.sourceNodeId,\n top: snapRect.bottom,\n ...lineData,\n });\n edgeLines.push({\n className: 'edge-full-right-mid',\n sourceNode: rightFullAlign.sourceNodeId,\n top: snapRect.top + snapRect.height / 2,\n dashed: true,\n ...lineData,\n });\n }\n\n const snappedEdgeLines = Object.entries(snapEdgeLines)\n .map(([direction, snapLine]) => {\n if (!snapLine) {\n return;\n }\n const sourceNode = this.document.getNode(snapLine.sourceNodeId);\n if (!sourceNode) {\n return;\n }\n const nodeRect = sourceNode.getData(FlowNodeTransformData).bounds;\n if (isNumber(snapLine.x)) {\n // 垂直\n const top = Math.min(nodeRect.top, snapRect.top);\n const bottom = Math.max(nodeRect.bottom, snapRect.bottom);\n const height = bottom - top;\n const left = snapLine.x;\n const width = this.options.edgeLineWidth;\n const isMidX = direction === 'midVertical';\n const lineData: SnapRenderLine = {\n className: `edge-snapped-${direction}`,\n sourceNode: snapLine.sourceNodeId,\n top,\n left,\n width,\n height,\n dashed: isMidX,\n };\n const onTop = top === nodeRect.top;\n if (onTop && topFullAlign) {\n return;\n }\n if (!onTop && bottomFullAlign) {\n return;\n }\n return lineData;\n } else if (isNumber(snapLine.y)) {\n // 水平\n const left = Math.min(nodeRect.left, snapRect.left);\n const right = Math.max(nodeRect.right, snapRect.right);\n const width = right - left;\n const top = snapLine.y;\n const height = this.options.edgeLineWidth;\n const isMidY = direction === 'midHorizontal';\n const lineData: SnapRenderLine = {\n className: `edge-snapped-${direction}`,\n sourceNode: snapLine.sourceNodeId,\n top,\n left,\n width,\n height,\n dashed: isMidY,\n };\n const onLeft = left === nodeRect.left;\n if (onLeft && leftFullAlign) {\n return;\n }\n if (!onLeft && rightFullAlign) {\n return;\n }\n return lineData;\n }\n })\n .filter(Boolean) as SnapRenderLine[];\n\n edgeLines.push(...snappedEdgeLines);\n\n return edgeLines;\n }\n\n private directionFullAlign(params: {\n alignRects: AlignRect[];\n targetRect: Rectangle;\n isVertical: boolean;\n }): AlignRect | undefined {\n const { alignRects, targetRect, isVertical } = params;\n let fullAlignIndex = -1;\n for (let i = 0; i < alignRects.length; i++) {\n const alignRect = alignRects[i];\n const prevRect = alignRects[i - 1]?.rect ?? targetRect;\n const isFullAlign = this.rectFullAlign(alignRect.rect, prevRect, isVertical);\n if (!isFullAlign) {\n // 未对齐则中断\n break; // 用 for 循环 + break 反而比 Array.findIndex 实现可读性更好\n }\n fullAlignIndex = i;\n }\n const fullAlignRect = alignRects[fullAlignIndex];\n return fullAlignRect;\n }\n\n private rectFullAlign(rectA: Rectangle, rectB: Rectangle, isVertical: boolean): boolean {\n if (isVertical) {\n return isEqual(rectA.left, rectB.left) && isEqual(rectA.right, rectB.right);\n } else {\n return isEqual(rectA.top, rectB.top) && isEqual(rectA.bottom, rectB.bottom);\n }\n }\n\n private calcAlignLines(event: SnapEvent): SnapRenderLine[] {\n const { alignRects, alignSpacing, snapRect } = event;\n\n const topAlignLines = this.calcDirectionAlignLines({\n alignRects: alignRects.top,\n targetRect: snapRect,\n isVertical: true,\n spacing: alignSpacing.midVertical ?? alignSpacing.top,\n });\n\n const bottomAlignLines = this.calcDirectionAlignLines({\n alignRects: alignRects.bottom,\n targetRect: snapRect,\n isVertical: true,\n spacing: alignSpacing.midVertical ?? alignSpacing.bottom,\n });\n\n const leftAlignLines = this.calcDirectionAlignLines({\n alignRects: alignRects.left,\n targetRect: snapRect,\n isVertical: false,\n spacing: alignSpacing.midHorizontal ?? alignSpacing.left,\n });\n\n const rightAlignLines = this.calcDirectionAlignLines({\n alignRects: alignRects.right,\n targetRect: snapRect,\n isVertical: false,\n spacing: alignSpacing.midHorizontal ?? alignSpacing.right,\n });\n\n return [...topAlignLines, ...bottomAlignLines, ...leftAlignLines, ...rightAlignLines];\n }\n\n private calcDirectionAlignLines(params: {\n alignRects: AlignRect[];\n targetRect: Rectangle;\n isVertical: boolean;\n spacing?: number;\n }) {\n const { alignRects, targetRect, isVertical, spacing } = params;\n const alignLines: SnapRenderLine[] = [];\n if (!spacing) {\n return alignLines;\n }\n for (let i = 0; i < alignRects.length; i++) {\n const alignRect = alignRects[i];\n const rect = alignRect.rect;\n const prevRect = alignRects[i - 1]?.rect ?? targetRect;\n\n const betweenSpacing = isVertical\n ? Math.min(Math.abs(prevRect.top - rect.bottom), Math.abs(prevRect.bottom - rect.top))\n : Math.min(Math.abs(prevRect.left - rect.right), Math.abs(prevRect.right - rect.left));\n if (!isEqual(betweenSpacing, spacing)) {\n // 不连续,需要中断\n break; // 因为要用到 break,所以不能用 Array.map()\n }\n if (isVertical) {\n const centerX = this.calcHorizontalIntersectionCenter(rect, targetRect);\n alignLines.push({\n className: 'align-vertical',\n sourceNode: alignRect.sourceNodeId,\n top: Math.min(rect.bottom, prevRect.bottom),\n left: centerX,\n width: 1,\n height: spacing,\n });\n } else {\n const centerY = this.calcVerticalIntersectionCenter(rect, targetRect);\n alignLines.push({\n className: 'align-horizontal',\n sourceNode: alignRect.sourceNodeId,\n top: centerY,\n left: Math.min(rect.right, prevRect.right),\n width: spacing,\n height: 1,\n });\n }\n }\n return alignLines;\n }\n\n private calcVerticalIntersectionCenter(rectA: Rectangle, rectB: Rectangle): number {\n const top = Math.max(rectA.top, rectB.top);\n const bottom = Math.min(rectA.bottom, rectB.bottom);\n return (top + bottom) / 2;\n }\n\n private calcHorizontalIntersectionCenter(rectA: Rectangle, rectB: Rectangle): number {\n const left = Math.max(rectA.left, rectB.left);\n const right = Math.min(rectA.right, rectB.right);\n return (left + right) / 2;\n }\n}\n"],"mappings":"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","names":["import_core","import_free_layout_core","import_document","import_inversify","import_utils","import_free_layout_core","import_document","import_core","React"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowgram.ai/free-snap-plugin",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.14",
|
|
4
4
|
"homepage": "https://flowgram.ai/",
|
|
5
5
|
"repository": "https://github.com/bytedance/flowgram.ai",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
"inversify": "^6.0.1",
|
|
20
20
|
"reflect-metadata": "~0.2.2",
|
|
21
21
|
"lodash-es": "^4.17.21",
|
|
22
|
-
"@flowgram.ai/core": "0.4.
|
|
23
|
-
"@flowgram.ai/
|
|
24
|
-
"@flowgram.ai/renderer": "0.4.
|
|
25
|
-
"@flowgram.ai/utils": "0.4.
|
|
26
|
-
"@flowgram.ai/
|
|
22
|
+
"@flowgram.ai/core": "0.4.14",
|
|
23
|
+
"@flowgram.ai/free-layout-core": "0.4.14",
|
|
24
|
+
"@flowgram.ai/renderer": "0.4.14",
|
|
25
|
+
"@flowgram.ai/utils": "0.4.14",
|
|
26
|
+
"@flowgram.ai/document": "0.4.14"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/bezier-js": "4.1.3",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"tsup": "^8.0.1",
|
|
40
40
|
"typescript": "^5.8.3",
|
|
41
41
|
"vitest": "^0.34.6",
|
|
42
|
-
"@flowgram.ai/eslint-config": "0.4.
|
|
43
|
-
"@flowgram.ai/ts-config": "0.4.
|
|
42
|
+
"@flowgram.ai/eslint-config": "0.4.14",
|
|
43
|
+
"@flowgram.ai/ts-config": "0.4.14"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"react": ">=16.8",
|