Skip to content

Commit bc10870

Browse files
authored
feat(sankey): update d3-sankey layout for depth customize (#2378)
* feat(depth): update di-sankey layout for depth customize * chore: remove unused * test: fix ci * chore: for cr * chore: update ci * chore: remove unused action
1 parent f281658 commit bc10870

File tree

14 files changed

+776
-243
lines changed

14 files changed

+776
-243
lines changed

.github/workflows/build.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: build
22

3-
on: ["push", "pull_request"]
3+
on: ["pull_request"]
44

55
jobs:
66
build:

.github/workflows/preview-build.yml

-26
This file was deleted.

.github/workflows/preview-upload.yml

-28
This file was deleted.
+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { Sankey } from '../../../../src';
2+
import { createDiv } from '../../../utils/dom';
3+
4+
describe('sankey', () => {
5+
it('nodeDepth', () => {
6+
const ALIPAY_DATA = [
7+
{ source: 'A', target: 'B', value: 160 },
8+
{ source: 'B', target: 'C', value: 10 },
9+
{ source: 'C', target: 'D', value: 8 },
10+
{ source: 'E', target: 'D', value: 27 },
11+
];
12+
13+
const sankey = new Sankey(createDiv(), {
14+
height: 500,
15+
data: ALIPAY_DATA,
16+
sourceField: 'source',
17+
targetField: 'target',
18+
weightField: 'value',
19+
nodeDepth: (node) => {
20+
switch (node.name) {
21+
case 'A':
22+
return 1;
23+
case 'B':
24+
return 0;
25+
case 'C':
26+
return 2;
27+
case 'D':
28+
return 2;
29+
// case 'E':
30+
// return 2;
31+
}
32+
return node.depth;
33+
},
34+
});
35+
36+
sankey.render();
37+
38+
const elements = sankey.chart.views[1].geometries[0].elements;
39+
// a 在 b 的右侧
40+
// @ts-ignore
41+
expect(elements[0].data.x[0]).toBeGreaterThan(elements[1].data.x[0]);
42+
43+
// a === e
44+
// @ts-ignore
45+
expect(elements[4].data.x[0]).toBe(elements[1].data.x[0]);
46+
47+
// c === d
48+
// @ts-ignore
49+
expect(elements[2].data.x[0]).toBe(elements[3].data.x[0]);
50+
51+
sankey.destroy();
52+
});
53+
});

__tests__/unit/utils/transform/sankey-spec.ts renamed to __tests__/unit/plots/sankey/layout-spec.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
import { sankeyLeft, sankeyJustify } from 'd3-sankey';
2-
import { sankeyLayout, getNodeAlignFunction, getDefaultOptions } from '../../../../src/utils/transform/sankey';
1+
import { left, justify } from '../../../../src/plots/sankey/sankey';
2+
import { sankeyLayout, getNodeAlignFunction, getDefaultOptions } from '../../../../src/plots/sankey/layout';
33
import { ENERGY } from '../../../data/sankey-energy';
44

55
describe('sankeyLayout', () => {
66
it('getNodeAlignFunction', () => {
7-
expect(getNodeAlignFunction(null, null)).toBe(sankeyJustify);
8-
expect(getNodeAlignFunction(undefined, null)).toBe(sankeyJustify);
7+
expect(getNodeAlignFunction(null, null)).toBe(justify);
8+
expect(getNodeAlignFunction(undefined, null)).toBe(justify);
99
// @ts-ignore
10-
expect(getNodeAlignFunction('middle', null)).toBe(sankeyJustify);
10+
expect(getNodeAlignFunction('middle', null)).toBe(justify);
1111

12-
expect(getNodeAlignFunction('left', null)).toBe(sankeyLeft);
12+
expect(getNodeAlignFunction('left', null)).toBe(left);
1313

1414
const fn = jest.fn();
1515
// @ts-ignore
1616
expect(getNodeAlignFunction(fn)).toBe(fn);
1717

18-
expect(getNodeAlignFunction(sankeyLeft, () => 1)).not.toBe(sankeyLeft);
18+
expect(getNodeAlignFunction(left, () => 1)).not.toBe(left);
1919

2020
// @ts-ignore
21-
expect(getNodeAlignFunction(123)).toBe(sankeyJustify);
21+
expect(getNodeAlignFunction(123)).toBe(justify);
2222
});
2323

2424
it('getDefaultOptions', () => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { M, randomFloat } from 'miz';
2+
import { sankey } from '../../../../../src/plots/sankey/sankey';
3+
import { cutoffCircle } from '../../../../../src/plots/sankey/circle';
4+
import { transformDataToNodeLinkData } from '../../../../../src/utils/data';
5+
6+
const C = [
7+
'A',
8+
'B',
9+
'C',
10+
'D',
11+
'E',
12+
'F',
13+
'G',
14+
'H',
15+
'I',
16+
'J',
17+
'K',
18+
'L',
19+
'M',
20+
'N',
21+
'O',
22+
'P',
23+
'K',
24+
'R',
25+
'S',
26+
'T',
27+
'U',
28+
'V',
29+
'W',
30+
'Z',
31+
'Y',
32+
'Z',
33+
];
34+
35+
describe('sankey', () => {
36+
it('monkey for deep', () => {
37+
for (let i = 0; i < 100; i++) {
38+
const layout = sankey()
39+
.nodeWidth(0.008)
40+
// @ts-ignore
41+
.nodePadding(0.02)
42+
.nodeAlign((_, maxDepth) => randomFloat(0, maxDepth, 0))
43+
.extent([
44+
[0, 0],
45+
[1, 1],
46+
]);
47+
48+
const data = M.arrayOf(
49+
M.shape({
50+
source: M.oneOf(C),
51+
target: M.oneOf(C),
52+
value: M.number(1, 10),
53+
}),
54+
10,
55+
50
56+
).mock();
57+
58+
const sankeyLayoutInputData = transformDataToNodeLinkData(
59+
cutoffCircle(data, 'source', 'target'),
60+
'source',
61+
'target',
62+
'value'
63+
);
64+
65+
// 不报错即可
66+
expect(() => {
67+
layout(sankeyLayoutInputData);
68+
}).not.toThrow();
69+
}
70+
});
71+
});

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858
"@antv/g2": "^4.1.0",
5959
"d3-hierarchy": "^2.0.0",
6060
"d3-regression": "^1.3.5",
61-
"d3-sankey": "^0.12.3",
6261
"size-sensor": "^1.0.1",
6362
"tslib": "^2.0.3"
6463
},
@@ -92,6 +91,7 @@
9291
"limit-size": "^0.1.3",
9392
"lint-md-cli": "^0.1.2",
9493
"lint-staged": "^10.0.7",
94+
"miz": "^1.0.1",
9595
"npm-run-all": "^4.1.5",
9696
"prettier": "^2.0.1",
9797
"react": "^16.11.0",

src/plots/sankey/helper.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { isRealNumber } from '../../utils/number';
22
import { transformDataToNodeLinkData } from '../../utils/data';
3-
import { sankeyLayout } from '../../utils/transform/sankey';
3+
import { sankeyLayout } from './layout';
44
import { cutoffCircle } from './circle';
55
import { SankeyOptions } from './types';
66

0 commit comments

Comments
 (0)