Skip to content

Commit 8bea653

Browse files
committed
feat(webworker): adding 15 algorithms support webworker, and adding unit tests
1 parent b58398f commit 8bea653

16 files changed

+1043
-31
lines changed

packages/graph/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"prettier": "prettier -c --write \"**/*\"",
3232
"test": "npm run build:umd && jest",
3333
"test-live": "npm run build:umd && DEBUG_MODE=1 jest --watch ./tests/unit/louvain-spec.ts",
34+
"test-live:async": "npm run build:umd && DEBUG_MODE=1 jest --watch ./tests/unit/*-async-spec.ts",
3435
"lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx"
3536
},
3637
"homepage": "https://g6.antv.vision",

packages/graph/src/index.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,23 @@ import minimumSpanningTree from './mts';
1414
import pageRank from './pageRank';
1515
import { getNeighbors } from './util';
1616
import Stack from './structs/stack';
17-
import { getDegreeAsync } from './workers/index';
17+
import {
18+
getAdjMatrixAsync,
19+
connectedComponentAsync,
20+
getDegreeAsync,
21+
getInDegreeAsync,
22+
getOutDegreeAsync,
23+
detectCycleAsync,
24+
dijkstraAsync,
25+
findAllPathAsync,
26+
findShortestPathAsync,
27+
floydWarshallAsync,
28+
labelPropagationAsync,
29+
louvainAsync,
30+
minimumSpanningTreeAsync,
31+
pageRankAsync,
32+
getNeighborsAsync,
33+
} from './workers/index';
1834

1935
export {
2036
getAdjMatrix,
@@ -34,7 +50,21 @@ export {
3450
minimumSpanningTree,
3551
pageRank,
3652
getNeighbors,
53+
getAdjMatrixAsync,
54+
connectedComponentAsync,
3755
getDegreeAsync,
56+
getInDegreeAsync,
57+
getOutDegreeAsync,
58+
detectCycleAsync,
59+
dijkstraAsync,
60+
findAllPathAsync,
61+
findShortestPathAsync,
62+
floydWarshallAsync,
63+
labelPropagationAsync,
64+
louvainAsync,
65+
minimumSpanningTreeAsync,
66+
pageRankAsync,
67+
getNeighborsAsync,
3868
};
3969

4070
export default {
@@ -55,5 +85,19 @@ export default {
5585
minimumSpanningTree,
5686
pageRank,
5787
getNeighbors,
88+
getAdjMatrixAsync,
89+
connectedComponentAsync,
5890
getDegreeAsync,
91+
getInDegreeAsync,
92+
getOutDegreeAsync,
93+
detectCycleAsync,
94+
dijkstraAsync,
95+
findAllPathAsync,
96+
findShortestPathAsync,
97+
floydWarshallAsync,
98+
labelPropagationAsync,
99+
louvainAsync,
100+
minimumSpanningTreeAsync,
101+
pageRankAsync,
102+
getNeighborsAsync,
59103
};
Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
export { default as getAdjMatrix } from '../adjacent-matrix'
2-
export { default as breadthFirstSearch } from '../bfs'
3-
export { default as connectedComponent } from '../connected-component'
4-
export { default as getDegree } from '../degree'
5-
export { getInDegree, getOutDegree } from '../degree'
6-
export { default as detectCycle } from '../detect-cycle'
7-
export { default as depthFirstSearch } from '../dfs'
8-
export { default as dijkstra } from '../dijkstra'
9-
export { findAllPath, findShortestPath } from '../find-path'
10-
export { default as floydWarshall } from '../floydWarshall'
11-
export { default as labelPropagation } from '../label-propagation'
12-
export { default as louvain } from '../louvain'
13-
export { default as minimumSpanningTree } from '../mts'
14-
export { default as pageRank } from '../pageRank'
15-
export { getNeighbors } from '../util'
1+
export { default as getAdjMatrix } from '../adjacent-matrix';
2+
export { default as breadthFirstSearch } from '../bfs';
3+
export { default as connectedComponent } from '../connected-component';
4+
export { default as getDegree } from '../degree';
5+
export { getInDegree, getOutDegree } from '../degree';
6+
export { default as detectCycle } from '../detect-cycle';
7+
export { default as depthFirstSearch } from '../dfs';
8+
export { default as dijkstra } from '../dijkstra';
9+
export { findAllPath, findShortestPath } from '../find-path';
10+
export { default as floydWarshall } from '../floydWarshall';
11+
export { default as labelPropagation } from '../label-propagation';
12+
export { default as louvain } from '../louvain';
13+
export { default as minimumSpanningTree } from '../mts';
14+
export { default as pageRank } from '../pageRank';
15+
export { getNeighbors } from '../util';

packages/graph/src/workers/createWorker.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@ const createWorker = <R>(type: string) => (...data) =>
1818
type,
1919
data,
2020
});
21-
21+
2222
worker.onmessage = (event: Event) => {
2323
const { data, type } = event.data;
2424
if (MESSAGE.SUCCESS === type) {
2525
resolve(data);
2626
} else {
2727
reject();
2828
}
29-
29+
3030
worker.terminate();
3131
};
32-
})
32+
});
3333
});
3434

3535
export default createWorker;
Lines changed: 187 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,197 @@
1-
import { GraphData, DegreeType } from '../types';
1+
import {
2+
GraphData,
3+
DegreeType,
4+
Matrix,
5+
IAlgorithmCallbacks,
6+
ClusterData,
7+
EdgeConfig,
8+
} from '../types';
29
import createWorker from './createWorker';
310
import { ALGORITHM } from './constant';
411

12+
/**
13+
* @param graphData 图数据
14+
* @param directed 是否为有向图
15+
*/
16+
const getAdjMatrixAsync = (graphData: GraphData, directed?: boolean) =>
17+
createWorker<Matrix[]>(ALGORITHM.getAdjMatrix)(...[graphData, directed]);
18+
19+
/**
20+
* 图的连通分量
21+
* @param graphData 图数据
22+
* @param directed 是否为有向图
23+
*/
24+
const connectedComponentAsync = (graphData: GraphData, directed?: boolean) =>
25+
createWorker<NodeConfig[][]>(ALGORITHM.connectedComponent)(...[graphData, directed]);
26+
527
/**
628
* 获取节点的度
729
* @param graphData 图数据
830
*/
931
const getDegreeAsync = (graphData: GraphData) =>
1032
createWorker<DegreeType>(ALGORITHM.getDegree)(graphData);
1133

12-
export { getDegreeAsync };
34+
/**
35+
* 获取节点的入度
36+
* @param graphData 图数据
37+
* @param nodeId 节点ID
38+
*/
39+
const getInDegreeAsync = (graphData: GraphData, nodeId: string) =>
40+
createWorker<DegreeType>(ALGORITHM.getInDegree)(graphData, nodeId);
41+
42+
/**
43+
* 获取节点的出度
44+
* @param graphData 图数据
45+
* @param nodeId 节点ID
46+
*/
47+
const getOutDegreeAsync = (graphData: GraphData, nodeId: string) =>
48+
createWorker<DegreeType>(ALGORITHM.getOutDegree)(graphData, nodeId);
49+
50+
/**
51+
* 检测图中的 Cycle
52+
* @param graphData 图数据
53+
*/
54+
const detectCycleAsync = (graphData: GraphData) =>
55+
createWorker<{
56+
[key: string]: string;
57+
}>(ALGORITHM.detectCycle)(graphData);
58+
59+
/**
60+
* Dijkstra's algorithm, See {@link https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm}
61+
* @param graphData 图数据
62+
*/
63+
const dijkstraAsync = (
64+
graphData: GraphData,
65+
source: string,
66+
directed?: boolean,
67+
weightPropertyName?: string,
68+
) =>
69+
createWorker<{
70+
length: number;
71+
path: any;
72+
}>(ALGORITHM.dijkstra)(...[graphData, source, directed, weightPropertyName]);
73+
74+
/**
75+
* 查找两点之间的所有路径
76+
* @param graphData 图数据
77+
* @param start 路径起始点ID
78+
* @param end 路径终点ID
79+
* @param directed 是否为有向图
80+
*/
81+
const findAllPathAsync = (graphData: GraphData, start: string, end: string, directed?: boolean) =>
82+
createWorker<string[][]>(ALGORITHM.findAllPath)(...[graphData, start, end, directed]);
83+
84+
/**
85+
* 查找两点之间的所有路径
86+
* @param graphData 图数据
87+
* @param start 路径起始点ID
88+
* @param end 路径终点ID
89+
* @param directed 是否为有向图
90+
* @param weightPropertyName 边权重的属名称,若数据中没有权重,则默认每条边权重为 1
91+
*/
92+
const findShortestPathAsync = (
93+
graphData: GraphData,
94+
start: string,
95+
end: string,
96+
directed?: boolean,
97+
weightPropertyName?: string,
98+
) =>
99+
createWorker<{
100+
length: number;
101+
path: any;
102+
}>(ALGORITHM.findShortestPath)(...[graphData, start, end, directed, weightPropertyName]);
103+
104+
/**
105+
* Floyd–Warshall algorithm, See {@link https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm}
106+
* @param graphData 图数据
107+
* @param directed 是否为有向图
108+
*/
109+
const floydWarshallAsync = (graphData: GraphData, directed?: boolean) =>
110+
createWorker<Matrix[]>(ALGORITHM.floydWarshall)(...[graphData, directed]);
111+
112+
/**
113+
* 标签传播算法
114+
* @param graphData 图数据
115+
* @param directed 是否有向图,默认为 false
116+
* @param weightPropertyName 权重的属性字段
117+
* @param maxIteration 最大迭代次数
118+
*/
119+
const labelPropagationAsync = (
120+
graphData: GraphData,
121+
directed: boolean,
122+
weightPropertyName: string,
123+
maxIteration: number,
124+
) =>
125+
createWorker<ClusterData>(ALGORITHM.labelPropagation)(
126+
graphData,
127+
directed,
128+
weightPropertyName,
129+
maxIteration,
130+
);
131+
132+
/**
133+
* 社区发现 louvain 算法
134+
* @param graphData 图数据
135+
* @param directed 是否有向图,默认为 false
136+
* @param weightPropertyName 权重的属性字段
137+
* @param threshold
138+
*/
139+
const louvainAsync = (
140+
graphData: GraphData,
141+
directed: boolean,
142+
weightPropertyName: string,
143+
threshold: number,
144+
) =>
145+
createWorker<ClusterData>(ALGORITHM.louvain)(graphData, directed, weightPropertyName, threshold);
146+
147+
/**
148+
* 最小生成树,See {@link https://en.wikipedia.org/wiki/Kruskal%27s_algorithm}
149+
* @param graph
150+
* @param weight 指定用于作为边权重的属性,若不指定,则认为所有边权重一致
151+
* @param algo 'prim' | 'kruskal' 算法类型
152+
* @return EdgeConfig[] 返回构成MST的边的数组
153+
*/
154+
const minimumSpanningTreeAsync = (graphData: GraphData, weight?: boolean, algo?: string) =>
155+
createWorker<EdgeConfig[]>(ALGORITHM.minimumSpanningTree)(...[graphData, weight, algo]);
156+
157+
/**
158+
* PageRank https://en.wikipedia.org/wiki/PageRank
159+
* refer: https://github.com/anvaka/ngraph.pagerank
160+
* @param graph
161+
* @param epsilon 判断是否收敛的精度值,默认 0.000001
162+
* @param linkProb 阻尼系数(dumping factor),指任意时刻,用户访问到某节点后继续访问该节点链接的下一个节点的概率,经验值 0.85
163+
*/
164+
const pageRankAsync = (graphData: GraphData, epsilon?: number, linkProb?: number) =>
165+
createWorker<{
166+
[key: string]: number;
167+
}>(ALGORITHM.pageRank)(...[graphData, epsilon, linkProb]);
168+
169+
/**
170+
* 获取指定节点的所有邻居
171+
* @param nodeId 节点 ID
172+
* @param edges 图中的所有边数据
173+
* @param type 邻居类型
174+
*/
175+
const getNeighborsAsync = (
176+
nodeId: string,
177+
edges: EdgeConfig[],
178+
type?: 'target' | 'source' | undefined,
179+
) => createWorker<string[]>(ALGORITHM.getNeighbors)(...[nodeId, edges, type]);
180+
181+
export {
182+
getAdjMatrixAsync,
183+
connectedComponentAsync,
184+
getDegreeAsync,
185+
getInDegreeAsync,
186+
getOutDegreeAsync,
187+
detectCycleAsync,
188+
dijkstraAsync,
189+
findAllPathAsync,
190+
findShortestPathAsync,
191+
floydWarshallAsync,
192+
labelPropagationAsync,
193+
louvainAsync,
194+
minimumSpanningTreeAsync,
195+
pageRankAsync,
196+
getNeighborsAsync,
197+
};

0 commit comments

Comments
 (0)