in src/chart/sankey/sankeyLayout.ts [111:188]
function computeNodeBreadths(
nodes: GraphNode[],
edges: GraphEdge[],
nodeWidth: number,
width: number,
height: number,
orient: LayoutOrient,
nodeAlign: SankeySeriesOption['nodeAlign']
) {
// Used to mark whether the edge is deleted. if it is deleted,
// the value is 0, otherwise it is 1.
const remainEdges = [];
// Storage each node's indegree.
const indegreeArr = [];
// Used to storage the node with indegree is equal to 0.
let zeroIndegrees: GraphNode[] = [];
let nextTargetNode: GraphNode[] = [];
let x = 0;
// let kx = 0;
for (let i = 0; i < edges.length; i++) {
remainEdges[i] = 1;
}
for (let i = 0; i < nodes.length; i++) {
indegreeArr[i] = nodes[i].inEdges.length;
if (indegreeArr[i] === 0) {
zeroIndegrees.push(nodes[i]);
}
}
let maxNodeDepth = -1;
// Traversing nodes using topological sorting to calculate the
// horizontal(if orient === 'horizontal') or vertical(if orient === 'vertical')
// position of the nodes.
while (zeroIndegrees.length) {
for (let idx = 0; idx < zeroIndegrees.length; idx++) {
const node = zeroIndegrees[idx];
const item = node.hostGraph.data.getRawDataItem(node.dataIndex) as SankeyNodeItemOption;
const isItemDepth = item.depth != null && item.depth >= 0;
if (isItemDepth && item.depth > maxNodeDepth) {
maxNodeDepth = item.depth;
}
node.setLayout({depth: isItemDepth ? item.depth : x}, true);
orient === 'vertical'
? node.setLayout({dy: nodeWidth}, true)
: node.setLayout({dx: nodeWidth}, true);
for (let edgeIdx = 0; edgeIdx < node.outEdges.length; edgeIdx++) {
const edge = node.outEdges[edgeIdx];
const indexEdge = edges.indexOf(edge);
remainEdges[indexEdge] = 0;
const targetNode = edge.node2;
const nodeIndex = nodes.indexOf(targetNode);
if (--indegreeArr[nodeIndex] === 0 && nextTargetNode.indexOf(targetNode) < 0) {
nextTargetNode.push(targetNode);
}
}
}
++x;
zeroIndegrees = nextTargetNode;
nextTargetNode = [];
}
for (let i = 0; i < remainEdges.length; i++) {
if (remainEdges[i] === 1) {
throw new Error('Sankey is a DAG, the original data has cycle!');
}
}
const maxDepth = maxNodeDepth > x - 1 ? maxNodeDepth : x - 1;
if (nodeAlign && nodeAlign !== 'left') {
adjustNodeWithNodeAlign(nodes, nodeAlign, orient, maxDepth);
}
const kx = orient === 'vertical'
? (height - nodeWidth) / maxDepth
: (width - nodeWidth) / maxDepth;
scaleNodeBreadths(nodes, kx, orient);
}