Skip to content

Commit

Permalink
feat(sankey): nodelink data supported (#2967)
Browse files Browse the repository at this point in the history
* fix(funnel): do not mutable data

* revert(funnel): clone data firstly

* chore: remove unused import

* feat(sankey): node link data supported
  • Loading branch information
hustcc authored Nov 12, 2021
1 parent ceb52ab commit bb9e01c
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 17 deletions.
38 changes: 38 additions & 0 deletions __tests__/unit/plots/sankey/node-link-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Sankey } from '../../../../src';
import { createDiv } from '../../../utils/dom';

describe('sankey', () => {
it('dataType = nodeLink', () => {
const ALIPAY_DATA = {
nodes: [
{ id: 'A', name: 'A' },
{ id: 'B', name: 'B' },
{ id: 'C', name: 'C' },
{ id: 'D', name: 'D' },
{ id: 'E', name: 'E' },
{ id: 'F', name: 'F', fixedValue: 10 },
],
links: [
{ source: 0, target: 1, value: 160 },
{ source: 1, target: 2, value: 10 },
{ source: 2, target: 3, value: 8 },
{ source: 4, target: 3, value: 27 },
],
};

const sankey = new Sankey(createDiv(), {
height: 500,
dataType: 'node-link',
data: ALIPAY_DATA,
});

sankey.render();

const elements = sankey.chart.views[1].geometries[0].elements;

// F 元素会现实出来
expect(elements.some((el) => el.getData().name === 'F')).toBe(true);

sankey.destroy();
});
});
35 changes: 26 additions & 9 deletions src/plots/sankey/helper.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import { isRealNumber, pick } from '../../utils';
import { transformDataToNodeLinkData } from '../../utils/data';
import { sankeyLayout } from './layout';
import { Data } from '../../types';
import { sankeyLayout, SankeyLayoutInputData } from './layout';
import { cutoffCircle } from './circle';
import { SankeyOptions } from './types';

/**
* 是否是 node-link 类型的数据结构
* @param dataTyp
* @returns
*/
function isNodeLink(dataType: string) {
return dataType === 'node-link';
}

export function getNodeWidthRatio(nodeWidth: number, nodeWidthRatio: number, width: number) {
return isRealNumber(nodeWidth) ? nodeWidth / width : nodeWidthRatio;
}
Expand All @@ -20,6 +30,7 @@ export function getNodePaddingRatio(nodePadding: number, nodePaddingRatio: numbe
*/
export function transformToViewsData(options: SankeyOptions, width: number, height: number) {
const {
dataType,
data,
sourceField,
targetField,
Expand All @@ -34,13 +45,19 @@ export function transformToViewsData(options: SankeyOptions, width: number, heig
rawFields = [],
} = options;

const sankeyLayoutInputData = transformDataToNodeLinkData(
cutoffCircle(data, sourceField, targetField),
sourceField,
targetField,
weightField,
rawFields
);
let sankeyLayoutInputData: unknown;

if (!isNodeLink(dataType)) {
sankeyLayoutInputData = transformDataToNodeLinkData(
cutoffCircle(data as Data, sourceField, targetField),
sourceField,
targetField,
weightField,
rawFields
);
} else {
sankeyLayoutInputData = data;
}

// 3. layout 之后的数据
const { nodes, links } = sankeyLayout(
Expand All @@ -51,7 +68,7 @@ export function transformToViewsData(options: SankeyOptions, width: number, heig
nodeSort,
nodeDepth,
},
sankeyLayoutInputData
sankeyLayoutInputData as SankeyLayoutInputData
);

// 4. 生成绘图数据
Expand Down
60 changes: 52 additions & 8 deletions src/plots/sankey/types.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,72 @@
import { Data, Options, State, StyleAttr } from '../../types';
import { NodeDepth, NodeSort } from './layout';

/**
* node-link 数据类型的结构
*/
export type NodeLinkData = {
/**
* 节点数据
*/
readonly nodes: {
/**
* id 唯一即可,一般可以直接等于 name
*/
readonly id: string;
/**
* 节点的名称,用于 UI 上的现实
*/
readonly name: string;
/**
* 节点的值,不传则节点大小有来源求和决定
*/
readonly fixedValue?: number;
}[];
/**
*
*/
readonly links: {
/**
* 来源节点在 nodes 中的 index
*/
readonly source: number;
/**
* 目标节点在 nodes 中的 index
*/
readonly target: number;
/**
* 边的值
*/
readonly value: number;
}[];
};

/** 配置类型定义 */
export interface SankeyOptions extends Omit<Options, 'xField' | 'yField' | 'xAxis' | 'yAxis'> {
export interface SankeyOptions extends Omit<Options, 'data' | 'xField' | 'yField' | 'xAxis' | 'yAxis'> {
/**
* 数据集的类型,默认为 detail
*/
readonly dataType?: 'node-link' | 'detail';
/**
* 来源字段
* 来源字段,dataType = 'node-link' 的时候,不用传
*/
readonly sourceField: string;
readonly sourceField?: string;
/**
* 去向字段
* 去向字段,dataType = 'node-link' 的时候,不用传
*/
readonly targetField: string;
readonly targetField?: string;
/**
* 权重字段
* 权重字段,dataType = 'node-link' 的时候,不用传
*/
readonly weightField: string;
readonly weightField?: string;
/**
* 附加的 元字段
*/
readonly rawFields?: string[];
/**
* 数据
*/
readonly data: Data;
readonly data: Data | NodeLinkData;
/**
* 节点宽度的比如,参考画布的宽度,默认值为 0.008
*/
Expand Down

0 comments on commit bb9e01c

Please sign in to comment.