Ver Fonte

perf(free-layout): optimize line interaction experience (#468)

* feat(drag): drag line support snapping to multiple input ports

* feat(drag): drag line support snapping to container node

* feat(node-panel): build line support multiple input ports

* feat(demo): not allow add line between different loop container
Louis Young há 6 meses atrás
pai
commit
f2a04c6219

+ 8 - 1
apps/demo-free-layout/src/hooks/use-editor-props.tsx

@@ -99,10 +99,17 @@ export function useEditorProps(
        * 判断是否连线
        */
       canAddLine(ctx, fromPort, toPort) {
-        // not the same node
+        // Cannot be a self-loop on the same node / 不能是同一节点自循环
         if (fromPort.node === toPort.node) {
           return false;
         }
+        // Cannot be in different loop containers - 不能在不同 Loop 容器
+        if (
+          toPort.node.parent?.flowNodeType === WorkflowNodeType.Loop &&
+          fromPort.node.parent?.id !== toPort.node.parent?.id
+        ) {
+          return false;
+        }
         /**
          * 线条环检测,不允许连接到前面的节点
          * Line loop detection, which is not allowed to connect to the node in front of it

+ 13 - 6
packages/canvas-engine/free-layout-core/src/service/workflow-drag-service.ts

@@ -646,13 +646,9 @@ export class WorkflowDragService {
         });
 
         this.setLineColor(line, this.linesManager.lineColor.drawing);
-        if (toNode && !this.isContainer(toNode)) {
+        if (toNode) {
           // 如果鼠标 hover 在 node 中的时候,默认连线到这个 node 的初始位置
-          const portsData = toNode.getData(WorkflowNodePortsData)!;
-          const { inputPorts } = portsData;
-          if (inputPorts.length === 1) {
-            toPort = inputPorts[0];
-          }
+          toPort = this.getNearestPort(toNode, dragPos);
           const { hasError } = this.handleDragOnNode(toNode, fromPort, line, toPort, originLine);
           lineErrorReset = hasError;
         }
@@ -783,4 +779,15 @@ export class WorkflowDragService {
       },
     };
   }
+
+  /** 获取最近的 port */
+  private getNearestPort(node: WorkflowNodeEntity, mousePos: IPoint): WorkflowPortEntity {
+    const portsData = node.getData(WorkflowNodePortsData)!;
+    const distanceSortedPorts = portsData.inputPorts.sort((a, b) => {
+      const aDistance = Math.abs(mousePos.y - a.point.y);
+      const bDistance = Math.abs(mousePos.y - b.point.y);
+      return aDistance - bDistance;
+    });
+    return distanceSortedPorts[0];
+  }
 }

+ 1 - 2
packages/plugins/free-node-panel-plugin/src/utils/build-line.ts

@@ -28,12 +28,11 @@ export const buildLine: IBuildLine = (params) => {
   const shouldBuildFromLine = portsData.inputPorts?.length > 0;
   if (fromPort && shouldBuildFromLine) {
     const toTargetPort = portsData.inputPorts[0];
-    const isSingleInput = portsData.inputPorts.length === 1;
     linesManager.createLine({
       from: fromPort.node.id,
       fromPort: fromPort.portID,
       to: node.id,
-      toPort: isSingleInput ? undefined : toTargetPort.id,
+      toPort: toTargetPort.portID,
     });
   }
   const shouldBuildToLine = portsData.outputPorts?.length > 0;