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> = {}; 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>, ) => { 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; } };