Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(extension): nodeGroupMap was not set correctly when adding a group #1268

Merged
merged 1 commit into from
Aug 7, 2023

Conversation

wbccb
Copy link
Contributor

@wbccb wbccb commented Aug 4, 2023

close #1261

问题发生的原因

issues/1261重现代码所示,当我们框选元素时,会触发

lf.addNode({
  type: "select-group",
  x: x1 + width / 2,
  y: y1 + height / 2,
  width,
  height,
  children: nodes.map((item) => item.id)
});

lf.addNode()会触发下面代码的执行

// packages/extension/src/materials/group/index.ts
lf.on('node:add,node:drop,node:dnd-add', this.appendNodeToGroup);

appendNodeToGroup = ({ data }) => {
    //...
    const nodeModel = this.lf.getNodeModelById(data.id);
    const bounds = nodeModel.getBounds();
    const group = this.getGroup(bounds, data);
    if (!group) return;
    //...
    if (nodeModel.isGroup) {
        // 如果这个节点是分组,那么将其子节点也记录下来
        data.children.forEach((nodeId) => {
            this.nodeGroupMap.set(nodeId, data.id);
        });
        this.nodeSelected({ data, isSelected: false, isMultiple: false });
    }
}

在上面这段代码中,由于this.getGroup()会一直返回null,因此会一直导致this.nodeGroupMap.set()这段代码无法执行

this.getGroup()会一直返回null是因为遍历所有nodes时,会筛选非自己本身的分组,即node.id !== nodeData.id,比如将issues/1261重现代码所有分组都删除了,然后我们框选一个分组,最终const { nodes } = this.lf.graphModel永远无法得到groups.length>0,因为唯一一个分组(node.isGroup)虽然满足node.isInRange(bounds),但是无法满足node.id !== nodeData.id

getGroup(bounds: Bounds, nodeData: BaseNodeModel): BaseNodeModel | undefined {
    const { nodes } = this.lf.graphModel;
    const groups = nodes.filter(
        node => node.isGroup && node.isInRange(bounds) && node.id !== nodeData.id,
    );
    if (groups.length === 0) return;
    //...
}

而没有正常设置this.nodeGroupMap为什么会出现折叠分组时出现虚拟线呢?

如下面代码所示,由于this.nodeGroupMap没有正常将新增的group数据添加进去,因此当我们使用this.graphModel.group.getNodeGroup(targetNodeId)总是会拿到空的值,从而不得不使用graphModel.getNodeModelById(targetNodeId)获取targetNodeIdGroup.id以及sourceNodeIdGroup.id,这就会导致了下面 this.createVirtualEdge(data)语句地执行。

本质就是拿不到node对应的groupId,所以只能拿它自己的nodeId,最终错误认为该node不属于分组,从而创建出虚拟边

// packages/extension/src/materials/group/GroupNode.ts
private foldEdge(isFolded, allEdges) {
    allEdges.forEach((edgeModel, index) => {
        //...
        let targetNodeIdGroup = this.graphModel.group.getNodeGroup(targetNodeId);
        // 考虑目标节点本来就是分组的情况
        if (!targetNodeIdGroup) {
            targetNodeIdGroup = this.graphModel.getNodeModelById(targetNodeId);
        }
        let sourceNodeIdGroup = this.graphModel.group.getNodeGroup(sourceNodeId);
        if (!sourceNodeIdGroup) {
            sourceNodeIdGroup = this.graphModel.getNodeModelById(sourceNodeId);
        }
        // 折叠时,处理未被隐藏的边的逻辑
        if (isFolded && edgeModel.visible !== false) {
            //...
            if (targetNodeIdGroup.id !== this.id || sourceNodeIdGroup.id !== this.id) {
                this.createVirtualEdge(data);
            }
            //...
        }
        //...
    });
}
// packages/extension/src/materials/group/index.ts
getNodeGroup(nodeId) {
    const groupId = this.nodeGroupMap.get(nodeId);
    if (groupId) {
        return this.lf.getNodeModelById(groupId);
    }
}

那为什么一开始初始化数据设置分组就不会出现这种情况(折叠分组时出现虚拟线)呢?

初始化数据时,会触发graphRendered()方法,在这个方法中,会进行this.nodeGroupMap.set(nodeId, node.id)的设置,因此不会产生上面的问题

graphRendered = (data) => {
    if (data && data.nodes) {
        data.nodes.forEach(node => {
            if (node.children) {
                node.children.forEach(nodeId => {
                    this.nodeGroupMap.set(nodeId, node.id);
                });
            }
        });
    }
};

解决方法

if (nodeModel.isGroup) {
    // 如果这个节点是分组,那么将其子节点也记录下来
    data.children.forEach((nodeId) => {
        this.nodeGroupMap.set(nodeId, data.id);
    });
    this.nodeSelected({ data, isSelected: false, isMultiple: false });
}

由于上面这段代码跟group没有关联关系,因此我们将它提前执行,如下面所示,我们在if (!group) return;之前提前执行,当添加group数据时,虽然我们通过this.getGroup(bounds, data)拿到的数据为空,但是我们也可以正确进行this.nodeGroupMap.set(nodeId, data.id)操作,从而避免了添加group数据没有正确设置this.nodeGroupMap的问题

const group = this.getGroup(bounds, data);
if (nodeModel.isGroup) {
    // 如果这个节点是分组,那么将其子节点也记录下来
    data.children.forEach((nodeId) => {
        this.nodeGroupMap.set(nodeId, data.id);
    });
    this.nodeSelected({ data, isSelected: false, isMultiple: false });
}
if (!group) return;
// ...省略一系列代码
// if (nodeModel.isGroup) {
//     // 如果这个节点是分组,那么将其子节点也记录下来
//     data.children.forEach((nodeId) => {
//         this.nodeGroupMap.set(nodeId, data.id);
//     });
//     this.nodeSelected({ data, isSelected: false, isMultiple: false });
// }

@towersxu towersxu merged commit 9b644e4 into didi:master Aug 7, 2023
@wbccb wbccb deleted the fix-1261 branch August 7, 2023 14:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants