Просмотр исходного кода

fix(core): support hover line or port in deep layer container (#443)

Louis Young 6 месяцев назад
Родитель
Сommit
0a9c3a0167

+ 2 - 0
packages/canvas-engine/free-layout-core/src/entities/workflow-line-entity.ts

@@ -66,6 +66,8 @@ export class WorkflowLineEntity extends Entity<WorkflowLineEntityOpts> {
 
   private _hasError = false;
 
+  public stackIndex = 0;
+
   /**
    * 线条数据
    */

+ 29 - 27
packages/canvas-engine/free-layout-core/src/workflow-lines-manager.ts

@@ -7,7 +7,7 @@ import { last } from 'lodash-es';
 import { inject, injectable } from 'inversify';
 import { DisposableCollection, Emitter, type IPoint } from '@flowgram.ai/utils';
 import { FlowNodeRenderData, FlowNodeTransformData } from '@flowgram.ai/document';
-import { EntityManager, PlaygroundConfigEntity, TransformData } from '@flowgram.ai/core';
+import { EntityManager, PlaygroundConfigEntity } from '@flowgram.ai/core';
 
 import { WorkflowDocumentOptions } from './workflow-document-option';
 import { type WorkflowDocument } from './workflow-document';
@@ -416,13 +416,8 @@ export class WorkflowLinesManager {
       .filter((port) => port.node.flowNodeType !== 'root');
     const targetPort = allPorts.find((port) => port.isHovered(pos.x, pos.y));
     if (targetPort) {
-      // 后创建的要先校验
-      const targetNode = this.document
-        .getAllNodes()
-        .slice()
-        .reverse()
-        .filter((node) => targetPort.node?.parent?.id !== node.id)
-        .find((node) => node.getData(TransformData)!.contains(pos.x, pos.y));
+      const containNodes = this.getContainNodesFromMousePos(pos);
+      const targetNode = last(containNodes);
       // 点位可能会被节点覆盖
       if (targetNode && targetNode !== targetPort.node) {
         return;
@@ -436,27 +431,9 @@ export class WorkflowLinesManager {
    * @param pos - 鼠标位置
    */
   getNodeFromMousePos(pos: IPoint): WorkflowNodeEntity | undefined {
-    const allNodes = this.document
-      .getAllNodes()
-      .sort((a, b) => this.getNodeIndex(a) - this.getNodeIndex(b));
     // 先挑选出 bounds 区域符合的 node
-    const containNodes: WorkflowNodeEntity[] = [];
     const { selection } = this.selectService;
-    const zoom =
-      this.entityManager.getEntity<PlaygroundConfigEntity>(PlaygroundConfigEntity)?.config?.zoom ||
-      1;
-    allNodes.forEach((node) => {
-      const { bounds } = node.getData<FlowNodeTransformData>(FlowNodeTransformData);
-      // 交互要求,节点边缘 4px 的时候就生效连线逻辑
-      if (
-        bounds
-          .clone()
-          .pad(4 / zoom)
-          .contains(pos.x, pos.y)
-      ) {
-        containNodes.push(node);
-      }
-    });
+    const containNodes = this.getContainNodesFromMousePos(pos);
     // 当有元素被选中的时候选中元素在顶层
     if (selection?.length) {
       const filteredNodes = containNodes.filter((node) =>
@@ -479,6 +456,31 @@ export class WorkflowLinesManager {
     line.addData(WorkflowLineRenderData);
   }
 
+  /** 获取鼠标坐标位置的所有节点(stackIndex 从小到大排序) */
+  private getContainNodesFromMousePos(pos: IPoint): WorkflowNodeEntity[] {
+    const allNodes = this.document
+      .getAllNodes()
+      .sort((a, b) => this.getNodeIndex(a) - this.getNodeIndex(b));
+    const zoom =
+      this.entityManager.getEntity<PlaygroundConfigEntity>(PlaygroundConfigEntity)?.config?.zoom ||
+      1;
+    const containNodes = allNodes
+      .map((node) => {
+        const { bounds } = node.getData<FlowNodeTransformData>(FlowNodeTransformData);
+        // 交互要求,节点边缘 4px 的时候就认为选中节点
+        if (
+          bounds
+            .clone()
+            .pad(4 / zoom)
+            .contains(pos.x, pos.y)
+        ) {
+          return node;
+        }
+      })
+      .filter(Boolean) as WorkflowNodeEntity[];
+    return containNodes;
+  }
+
   private getNodeIndex(node: WorkflowNodeEntity): number {
     const nodeRenderData = node.getData(FlowNodeRenderData);
     return nodeRenderData.stackIndex;

+ 11 - 17
packages/plugins/free-hover-plugin/src/hover-layer.tsx

@@ -236,38 +236,32 @@ export class HoverLayer extends Layer<HoverLayerOptions> {
       }
     }
 
-    const nodeInContainer = !!(nodeHovered?.parent && nodeHovered.parent.flowNodeType !== 'root');
-
     // 获取最接近的线条
     // 线条会相交需要获取最接近点位的线条,不能删除的线条不能被选中
     const lineHovered = checkTargetFromLine
       ? this.linesManager.getCloseInLineFromMousePos(mousePos)
       : undefined;
-    const lineInContainer = !!lineHovered?.inContainer;
 
-    // 判断容器内节点是否 hover
-    if (nodeHovered && nodeInContainer) {
-      this.updateHoveredKey(nodeHovered.id);
-      return;
-    }
-    // 判断容器内线条是否 hover
-    if (lineHovered && lineInContainer) {
-      this.updateHoveredKey(lineHovered.id);
-      return;
+    if (nodeHovered && lineHovered) {
+      const nodeStackIndex = nodeHovered.renderData.stackIndex;
+      const lineStackIndex = lineHovered.stackIndex;
+      if (nodeStackIndex > lineStackIndex) {
+        return this.updateHoveredKey(nodeHovered.id);
+      } else {
+        return this.updateHoveredKey(lineHovered.id);
+      }
     }
 
     // 判断节点是否 hover
     if (nodeHovered) {
-      this.updateHoveredKey(nodeHovered.id);
-      return;
+      return this.updateHoveredKey(nodeHovered.id);
     }
     // 判断线条是否 hover
     if (lineHovered) {
-      this.hoverService.updateHoveredKey(lineHovered.id);
-      return;
+      return this.updateHoveredKey(lineHovered.id);
     }
 
-    // 上述逻辑都未命中 则清空 hoverd
+    // 上述逻辑都未命中 则清空 hovered
     hoverService.clearHovered();
 
     const currentState = this.editorStateConfig.getCurrentState();

+ 8 - 5
packages/plugins/free-stack-plugin/src/manager.ts

@@ -80,23 +80,26 @@ export class StackingContextManager {
       const element = nodeRenderData.node;
       element.style.position = 'absolute';
       if (level === undefined) {
-        element.style.zIndex = 'auto';
         nodeRenderData.stackIndex = 0;
+        element.style.zIndex = 'auto';
         return;
       }
-      const stackIndex = StackingConfig.startIndex + level;
-      element.style.zIndex = String(stackIndex);
-      nodeRenderData.stackIndex = stackIndex;
+      nodeRenderData.stackIndex = level;
+      const zIndex = StackingConfig.startIndex + level;
+      element.style.zIndex = String(zIndex);
     });
     this.lines.forEach((line) => {
       const level = lineLevel.get(line.id);
       const element = line.node;
       element.style.position = 'absolute';
       if (level === undefined) {
+        line.stackIndex = 0;
         element.style.zIndex = 'auto';
         return;
       }
-      element.style.zIndex = String(StackingConfig.startIndex + level);
+      line.stackIndex = level;
+      const zIndex = StackingConfig.startIndex + level;
+      element.style.zIndex = String(zIndex);
     });
   }