Skip to content

Commit bb9e01c

Browse files
authored
feat(sankey): nodelink data supported (#2967)
* fix(funnel): do not mutable data * revert(funnel): clone data firstly * chore: remove unused import * feat(sankey): node link data supported
1 parent ceb52ab commit bb9e01c

File tree

3 files changed

+116
-17
lines changed

3 files changed

+116
-17
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Sankey } from '../../../../src';
2+
import { createDiv } from '../../../utils/dom';
3+
4+
describe('sankey', () => {
5+
it('dataType = nodeLink', () => {
6+
const ALIPAY_DATA = {
7+
nodes: [
8+
{ id: 'A', name: 'A' },
9+
{ id: 'B', name: 'B' },
10+
{ id: 'C', name: 'C' },
11+
{ id: 'D', name: 'D' },
12+
{ id: 'E', name: 'E' },
13+
{ id: 'F', name: 'F', fixedValue: 10 },
14+
],
15+
links: [
16+
{ source: 0, target: 1, value: 160 },
17+
{ source: 1, target: 2, value: 10 },
18+
{ source: 2, target: 3, value: 8 },
19+
{ source: 4, target: 3, value: 27 },
20+
],
21+
};
22+
23+
const sankey = new Sankey(createDiv(), {
24+
height: 500,
25+
dataType: 'node-link',
26+
data: ALIPAY_DATA,
27+
});
28+
29+
sankey.render();
30+
31+
const elements = sankey.chart.views[1].geometries[0].elements;
32+
33+
// F 元素会现实出来
34+
expect(elements.some((el) => el.getData().name === 'F')).toBe(true);
35+
36+
sankey.destroy();
37+
});
38+
});

src/plots/sankey/helper.ts

+26-9
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
import { isRealNumber, pick } from '../../utils';
22
import { transformDataToNodeLinkData } from '../../utils/data';
3-
import { sankeyLayout } from './layout';
3+
import { Data } from '../../types';
4+
import { sankeyLayout, SankeyLayoutInputData } from './layout';
45
import { cutoffCircle } from './circle';
56
import { SankeyOptions } from './types';
67

8+
/**
9+
* 是否是 node-link 类型的数据结构
10+
* @param dataTyp
11+
* @returns
12+
*/
13+
function isNodeLink(dataType: string) {
14+
return dataType === 'node-link';
15+
}
16+
717
export function getNodeWidthRatio(nodeWidth: number, nodeWidthRatio: number, width: number) {
818
return isRealNumber(nodeWidth) ? nodeWidth / width : nodeWidthRatio;
919
}
@@ -20,6 +30,7 @@ export function getNodePaddingRatio(nodePadding: number, nodePaddingRatio: numbe
2030
*/
2131
export function transformToViewsData(options: SankeyOptions, width: number, height: number) {
2232
const {
33+
dataType,
2334
data,
2435
sourceField,
2536
targetField,
@@ -34,13 +45,19 @@ export function transformToViewsData(options: SankeyOptions, width: number, heig
3445
rawFields = [],
3546
} = options;
3647

37-
const sankeyLayoutInputData = transformDataToNodeLinkData(
38-
cutoffCircle(data, sourceField, targetField),
39-
sourceField,
40-
targetField,
41-
weightField,
42-
rawFields
43-
);
48+
let sankeyLayoutInputData: unknown;
49+
50+
if (!isNodeLink(dataType)) {
51+
sankeyLayoutInputData = transformDataToNodeLinkData(
52+
cutoffCircle(data as Data, sourceField, targetField),
53+
sourceField,
54+
targetField,
55+
weightField,
56+
rawFields
57+
);
58+
} else {
59+
sankeyLayoutInputData = data;
60+
}
4461

4562
// 3. layout 之后的数据
4663
const { nodes, links } = sankeyLayout(
@@ -51,7 +68,7 @@ export function transformToViewsData(options: SankeyOptions, width: number, heig
5168
nodeSort,
5269
nodeDepth,
5370
},
54-
sankeyLayoutInputData
71+
sankeyLayoutInputData as SankeyLayoutInputData
5572
);
5673

5774
// 4. 生成绘图数据

src/plots/sankey/types.ts

+52-8
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,72 @@
11
import { Data, Options, State, StyleAttr } from '../../types';
22
import { NodeDepth, NodeSort } from './layout';
33

4+
/**
5+
* node-link 数据类型的结构
6+
*/
7+
export type NodeLinkData = {
8+
/**
9+
* 节点数据
10+
*/
11+
readonly nodes: {
12+
/**
13+
* id 唯一即可,一般可以直接等于 name
14+
*/
15+
readonly id: string;
16+
/**
17+
* 节点的名称,用于 UI 上的现实
18+
*/
19+
readonly name: string;
20+
/**
21+
* 节点的值,不传则节点大小有来源求和决定
22+
*/
23+
readonly fixedValue?: number;
24+
}[];
25+
/**
26+
*
27+
*/
28+
readonly links: {
29+
/**
30+
* 来源节点在 nodes 中的 index
31+
*/
32+
readonly source: number;
33+
/**
34+
* 目标节点在 nodes 中的 index
35+
*/
36+
readonly target: number;
37+
/**
38+
* 边的值
39+
*/
40+
readonly value: number;
41+
}[];
42+
};
43+
444
/** 配置类型定义 */
5-
export interface SankeyOptions extends Omit<Options, 'xField' | 'yField' | 'xAxis' | 'yAxis'> {
45+
export interface SankeyOptions extends Omit<Options, 'data' | 'xField' | 'yField' | 'xAxis' | 'yAxis'> {
46+
/**
47+
* 数据集的类型,默认为 detail
48+
*/
49+
readonly dataType?: 'node-link' | 'detail';
650
/**
7-
* 来源字段
51+
* 来源字段,dataType = 'node-link' 的时候,不用传
852
*/
9-
readonly sourceField: string;
53+
readonly sourceField?: string;
1054
/**
11-
* 去向字段
55+
* 去向字段,dataType = 'node-link' 的时候,不用传
1256
*/
13-
readonly targetField: string;
57+
readonly targetField?: string;
1458
/**
15-
* 权重字段
59+
* 权重字段,dataType = 'node-link' 的时候,不用传
1660
*/
17-
readonly weightField: string;
61+
readonly weightField?: string;
1862
/**
1963
* 附加的 元字段
2064
*/
2165
readonly rawFields?: string[];
2266
/**
2367
* 数据
2468
*/
25-
readonly data: Data;
69+
readonly data: Data | NodeLinkData;
2670
/**
2771
* 节点宽度的比如,参考画布的宽度,默认值为 0.008
2872
*/

0 commit comments

Comments
 (0)