问题表现
最近在做一个流程图,绘图部分使用antd/x6,node的位置信息使用Graph生成,在完成基本功能开发后发现一个小问题,本来预期node是向上对齐的,但是Graph没有让本该处于同一ranker的node处于同一个ranker而是尽可能地提升node的ranker,造成了node向下对齐的效果, 问题如下图所示:4号node逻辑上应该处于ranker1,Graph却让它处于ranker2
解决方案
Graph不支持直接设置node的ranker,但是可以设置edge的minlen,也就是设置一条边的起点和终点相差几个ranker;参考了这个链接后得到启发,通过设置node的输出边的minlen可以修改node的ranker。要让4号node处于ranker1就要设置4号node到终点的这条edge的minlen为2, 这样这个问题就可以得出这样一个解决方案:
计算出所有分支的路径,得出最长的路径的长度,然后给每条路径的最后一条edge设置相应的minlen就可以调整该路径上的所有node的ranker以实现node的向上对齐,minlen的设置规则为最长路径的长度-当前路径的长度+1
1.计算出所有分支的路径
//传入edges和起点的id,返回的数据为一个二维数组,每一个item就是一条路径,按照上图的edges数据
//得到的结果为[[0,1,2,4],[0,3,4]]
export function findAllPath(edges, starting) {
const endMap = {};
edges.forEach(({ start, end }) => {
if (endMap[start]) {
endMap[start].push(end);
} else {
endMap[start] = [end];
}
});
function generatePath(lastPaths) {
const newPath = [];
lastPaths.forEach((d) => {
const id = d[d.length - 1];
if (!endMap[id]) {
newPath.push(d);
} else {
endMap[id].forEach((b) => {
const temp = [...d, b];
generatePath([temp]).forEach((a) => {
newPath.push(a);
});
});
}
});
return newPath;
}
return generatePath([[starting]]);
}
2.得到最长路径的长度
const allPath = findAllPath(edge, starting);
let maxLength = 0;
allPath.forEach((d) => {
if (d.length > maxLength) {
maxLength = d.length;
}
});
3.动态生成每一条路径最后一条edge的minlen,并把数据传入graph
edges.forEach((edge) => {
const source = edge.getSource();
const target = edge.getTarget();
let minlen = 1;
//边的target是终点时才需要动态计算
if (target.cell === terminal) {
allPath.forEach((d) => {
if (d.includes(source.cell)) {
minlen = maxLength - d.length + 1;
}
});
}
g.setEdge(source.cell, target.cell, { minlen });
});
4.经过上面的一番操作后完美解决了这个问题,一家人就该齐齐整整
结论
Graph虽然无法单独设置单个node的ranker,但是可以通过设置它的输出边的minlen为一个比较大的数值来把它以及它上面的node顶上若干个ranker