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

This commit is contained in:
Louis Young 2025-07-02 16:46:38 +08:00 committed by GitHub
parent 522bc0770d
commit 0a9c3a0167
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 50 additions and 49 deletions

View File

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

View File

@ -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;

View File

@ -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();

View File

@ -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);
});
}