@antv/layout
Version:
graph layout algorithm
112 lines (101 loc) • 3.18 kB
text/typescript
import type { ID } from '../../../types';
import { DagreGraph } from '../graph';
import { barycenter } from './barycenter';
import resolveConflicts, { ConflictEntry } from './resolve-conflicts';
import { sort } from './sort';
export const sortSubgraph = (
g: DagreGraph,
v: ID,
cg: DagreGraph,
biasRight?: boolean,
usePrev?: boolean,
keepNodeOrder?: boolean,
) => {
let movable = g.getChildren(v).map((n) => n.id);
// fixorder的点不参与排序(这个方案不合适,只排了新增节点,和原来的分离)
const node = g.getNode(v)!;
const bl = node ? (node.data.borderLeft as ID) : undefined;
const br = node ? (node.data.borderRight as ID) : undefined;
const subgraphs: Record<string, Partial<ConflictEntry>> = {};
if (bl) {
movable = movable?.filter((w) => {
return w !== bl && w !== br;
});
}
const barycenters = barycenter(g, movable || []);
barycenters?.forEach((entry) => {
if (g.getChildren(entry.v)?.length) {
const subgraphResult = sortSubgraph(
g,
entry.v,
cg,
biasRight,
keepNodeOrder,
);
subgraphs[entry.v] = subgraphResult;
if (subgraphResult.hasOwnProperty('barycenter')) {
mergeBarycenters(entry, subgraphResult);
}
}
});
const entries = resolveConflicts(barycenters, cg);
expandSubgraphs(entries, subgraphs);
// 添加fixorder信息到entries里边
// TODO: 不考虑复合情况,只用第一个点的fixorder信息,后续考虑更完备的实现
entries
.filter((e) => e.vs.length > 0)
?.forEach((e) => {
const node = g.getNode(e.vs[0])!;
if (node) {
e.fixorder = node.data.fixorder!;
e.order = node.data.order!;
}
});
const result = sort(entries, biasRight, usePrev, keepNodeOrder);
if (bl) {
result.vs = [bl, result.vs, br].flat() as ID[];
if (g.getPredecessors(bl)?.length) {
const blPred = g.getNode(g.getPredecessors(bl)?.[0].id || '')!;
const brPred = g.getNode(g.getPredecessors(br!)?.[0].id || '')!;
if (!result.hasOwnProperty('barycenter')) {
result.barycenter = 0;
result.weight = 0;
}
result.barycenter =
(result.barycenter! * result.weight! +
blPred.data.order! +
brPred.data.order!) /
(result.weight! + 2);
result.weight! += 2;
}
}
return result;
};
const expandSubgraphs = (
entries: ConflictEntry[],
subgraphs: Record<string, Partial<ConflictEntry>>,
) => {
entries?.forEach((entry) => {
const vss = entry.vs?.map((v: ID) => {
if (subgraphs[v]) {
return subgraphs[v].vs!;
}
return v;
});
entry.vs = vss.flat();
});
};
const mergeBarycenters = (
target: { weight?: number; barycenter?: number },
other: { weight?: number; barycenter?: number },
) => {
if (target.barycenter !== undefined) {
target.barycenter =
(target.barycenter * target.weight! + other.barycenter! * other.weight!) /
(target.weight! + other.weight!);
target.weight! += other.weight!;
} else {
target.barycenter = other.barycenter;
target.weight = other.weight;
}
};