Skip to content

Commit

Permalink
feat: support maxNodeHeight and maxLinkHeight, crossNodeAlign v…
Browse files Browse the repository at this point in the history
…alue `parent` in sankey
  • Loading branch information
xile611 committed Nov 28, 2024
1 parent 505340d commit 453ad33
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 6 deletions.
11 changes: 10 additions & 1 deletion packages/vgrammar-sankey/src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export interface SankeyOptions {
* the align type of y position of nodes is differnt layer when the direction is `hotizontal`
* the align type of x position of nodes is differnt layer when the direction is `hotizontal`
*/
crossNodeAlign?: 'start' | 'end' | 'middle';
crossNodeAlign?: 'start' | 'end' | 'middle' | 'parent';
/**
* The align type of all the nodes
*/
Expand Down Expand Up @@ -71,13 +71,22 @@ export interface SankeyOptions {
* It's recommended to be smaller than 5px
*/
minNodeHeight?: number;
/**
* the maximal size of node when data is not zero or null
* this configuration can be used to avoid too large node to be seen when data is too big
*/
maxNodeHeight?: number;
/**
* The minimal size of link when data is not zero or null
* This configuration can be used to avoid too thin link to be seen when data is too small
* It's recommended to be smaller than 5px
* This option should be smaller than `minNodeHeight` when both options are specified
*/
minLinkHeight?: number;
/**
* the maximal size of link when data is not zero or null
*/
maxLinkHeight?: number;
/** the iteration count of layout */
iterations?: number;
/** parse the key of node, the defaultValue */
Expand Down
44 changes: 39 additions & 5 deletions packages/vgrammar-sankey/src/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -642,10 +642,17 @@ export class SankeyLayout {
initializeNodeBreadths(columns: SankeyNodeElement[][]) {
const minLinkHeight = this.options.minLinkHeight ?? 0;
let minNodeHeight = this.options.minNodeHeight ?? 0;
const maxNodeHeight = this.options.maxNodeHeight ?? Infinity;
let maxLinkHeight = this.options.maxLinkHeight;

if (isNil(minNodeHeight) || minNodeHeight < minLinkHeight) {
minNodeHeight = minLinkHeight;
}

if (isNil(maxLinkHeight) || maxLinkHeight > maxNodeHeight) {
maxLinkHeight = maxNodeHeight;
}

let ky = 0;
let getGapY: (node: SankeyNodeElement) => number = null;
let forceNodeHeight: number = null;
Expand Down Expand Up @@ -711,10 +718,13 @@ export class SankeyLayout {
sourceNodeHeight: number
) => number)
: (link: SankeyLinkElement, sourceNode: SankeyNodeElement, sourceNodeHeight: number) => {
return Math.max(
sourceNode.value ? sourceNodeHeight * linkClampe(link.value / sourceNode.value) : 0,
minLinkHeight,
0
return Math.min(
Math.max(
sourceNode.value ? sourceNodeHeight * linkClampe(link.value / sourceNode.value) : 0,
minLinkHeight,
0
),
maxLinkHeight
);
};

Expand All @@ -738,7 +748,7 @@ export class SankeyLayout {
}

calculatedNodeHeight = getNodeHeight(node);
nodeHeight = Math.max(calculatedNodeHeight, minNodeHeight);
nodeHeight = Math.min(Math.max(calculatedNodeHeight, minNodeHeight), maxNodeHeight);

node.y0 = y;
node.y1 = y + nodeHeight;
Expand All @@ -762,6 +772,30 @@ export class SankeyLayout {
node.y0 += deltaY;
node.y1 += deltaY;
}
} else if (this.options.crossNodeAlign === 'parent') {
const sourceNodes = nodes.reduce((res: Record<string, boolean>, node) => {
if (node.targetLinks && node.targetLinks.length) {
node.targetLinks.forEach(link => {
res[link.source] = true;
});
}
return res;
}, {});

if (Object.keys(sourceNodes).length && columns[i - 1] && columns[i - 1].length) {
const prevSourceNodes = columns[i - 1].filter(node => sourceNodes[node.key]);

if (prevSourceNodes && prevSourceNodes.length && prevSourceNodes[0].y0 !== nodes[0].y0) {
const startY = prevSourceNodes[0].y0;
const newDeltaY = startY - nodes[0].y0;

for (let j = 0, len = nodes.length; j < len; ++j) {
const node = nodes[j];
node.y0 += newDeltaY;
node.y1 += newDeltaY;
}
}
}
} else {
deltaY = deltaY / (nodes.length + 1);
for (let j = 0, len = nodes.length; j < len; ++j) {
Expand Down

0 comments on commit 453ad33

Please sign in to comment.