@antv/layout 1.2.13 → 1.2.14-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/85db61ddc757dae66e04.worker.js +2 -0
- package/dist/85db61ddc757dae66e04.worker.js.map +1 -0
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/lib/{dagre → antv-dagre}/acyclic.d.ts +1 -1
- package/lib/antv-dagre/acyclic.js +61 -0
- package/lib/antv-dagre/acyclic.js.map +1 -0
- package/lib/{dagre → antv-dagre}/add-border-segments.js +12 -12
- package/lib/antv-dagre/add-border-segments.js.map +1 -0
- package/lib/{dagre → antv-dagre}/coordinate-system.d.ts +2 -1
- package/lib/antv-dagre/coordinate-system.js +65 -0
- package/lib/antv-dagre/coordinate-system.js.map +1 -0
- package/lib/{dagre → antv-dagre}/data/list.d.ts +1 -1
- package/lib/{dagre → antv-dagre}/data/list.js +20 -22
- package/lib/antv-dagre/data/list.js.map +1 -0
- package/lib/{dagre → antv-dagre}/greedy-fas.d.ts +2 -2
- package/lib/antv-dagre/greedy-fas.js +136 -0
- package/lib/antv-dagre/greedy-fas.js.map +1 -0
- package/lib/{dagre → antv-dagre}/layout.d.ts +2 -1
- package/lib/{dagre → antv-dagre}/layout.js +125 -127
- package/lib/antv-dagre/layout.js.map +1 -0
- package/lib/{dagre → antv-dagre}/nesting-graph.js +36 -37
- package/lib/antv-dagre/nesting-graph.js.map +1 -0
- package/lib/{dagre → antv-dagre}/normalize.d.ts +2 -2
- package/lib/{dagre → antv-dagre}/normalize.js +24 -24
- package/lib/antv-dagre/normalize.js.map +1 -0
- package/lib/{dagre → antv-dagre}/order/add-subgraph-constraints.js +9 -9
- package/lib/antv-dagre/order/add-subgraph-constraints.js.map +1 -0
- package/lib/{dagre → antv-dagre}/order/barycenter.d.ts +2 -2
- package/lib/{dagre → antv-dagre}/order/barycenter.js +8 -8
- package/lib/antv-dagre/order/barycenter.js.map +1 -0
- package/lib/{dagre → antv-dagre}/order/build-layer-graph.js +18 -22
- package/lib/antv-dagre/order/build-layer-graph.js.map +1 -0
- package/lib/antv-dagre/order/cross-count.d.ts +3 -0
- package/lib/{dagre → antv-dagre}/order/cross-count.js +17 -17
- package/lib/antv-dagre/order/cross-count.js.map +1 -0
- package/lib/{dagre → antv-dagre}/order/index.d.ts +1 -1
- package/lib/{dagre → antv-dagre}/order/index.js +35 -35
- package/lib/antv-dagre/order/index.js.map +1 -0
- package/lib/{dagre → antv-dagre}/order/init-data-order.js +8 -9
- package/lib/antv-dagre/order/init-data-order.js.map +1 -0
- package/lib/antv-dagre/order/init-order.js +47 -0
- package/lib/antv-dagre/order/init-order.js.map +1 -0
- package/lib/{dagre → antv-dagre}/order/resolve-conflicts.d.ts +3 -3
- package/lib/{dagre → antv-dagre}/order/resolve-conflicts.js +32 -35
- package/lib/antv-dagre/order/resolve-conflicts.js.map +1 -0
- package/lib/{dagre → antv-dagre}/order/sort-subgraph.js +20 -20
- package/lib/antv-dagre/order/sort-subgraph.js.map +1 -0
- package/lib/{dagre → antv-dagre}/order/sort.d.ts +2 -2
- package/lib/{dagre → antv-dagre}/order/sort.js +19 -19
- package/lib/antv-dagre/order/sort.js.map +1 -0
- package/lib/{dagre → antv-dagre}/parent-dummy-chains.js +28 -28
- package/lib/antv-dagre/parent-dummy-chains.js.map +1 -0
- package/lib/{dagre → antv-dagre}/position/bk.d.ts +5 -4
- package/lib/{dagre → antv-dagre}/position/bk.js +140 -143
- package/lib/antv-dagre/position/bk.js.map +1 -0
- package/lib/{dagre → antv-dagre}/position/index.d.ts +2 -1
- package/lib/antv-dagre/position/index.js +51 -0
- package/lib/antv-dagre/position/index.js.map +1 -0
- package/lib/{dagre → antv-dagre}/rank/feasible-tree.d.ts +2 -2
- package/lib/{dagre → antv-dagre}/rank/feasible-tree.js +32 -32
- package/lib/antv-dagre/rank/feasible-tree.js.map +1 -0
- package/lib/antv-dagre/rank/index.d.ts +2 -0
- package/lib/{dagre → antv-dagre}/rank/index.js +10 -10
- package/lib/antv-dagre/rank/index.js.map +1 -0
- package/lib/{dagre → antv-dagre}/rank/network-simplex.d.ts +2 -2
- package/lib/{dagre → antv-dagre}/rank/network-simplex.js +70 -71
- package/lib/antv-dagre/rank/network-simplex.js.map +1 -0
- package/lib/{dagre → antv-dagre}/rank/util.d.ts +2 -2
- package/lib/{dagre → antv-dagre}/rank/util.js +31 -31
- package/lib/antv-dagre/rank/util.js.map +1 -0
- package/lib/antv-dagre/types.d.ts +2 -0
- package/lib/antv-dagre/types.js +2 -0
- package/lib/antv-dagre/types.js.map +1 -0
- package/lib/{dagre → antv-dagre}/util.d.ts +1 -1
- package/lib/{dagre → antv-dagre}/util.js +90 -98
- package/lib/antv-dagre/util.js.map +1 -0
- package/lib/antv-dagre.d.ts +50 -0
- package/lib/antv-dagre.js +538 -0
- package/lib/antv-dagre.js.map +1 -0
- package/lib/bundle-entry.d.ts +2 -18
- package/lib/bundle-entry.js +2 -18
- package/lib/bundle-entry.js.map +1 -1
- package/lib/bundle-supervisor.d.ts +4 -22
- package/lib/bundle-supervisor.js +54 -53
- package/lib/bundle-supervisor.js.map +1 -1
- package/lib/bundle-worker.d.ts +1 -1
- package/lib/bundle-worker.js +31 -33
- package/lib/bundle-worker.js.map +1 -1
- package/lib/circular.d.ts +1 -1
- package/lib/circular.js +124 -140
- package/lib/circular.js.map +1 -1
- package/lib/comboCombined.d.ts +1 -1
- package/lib/comboCombined.js +254 -284
- package/lib/comboCombined.js.map +1 -1
- package/lib/concentric.d.ts +1 -1
- package/lib/concentric.js +166 -176
- package/lib/concentric.js.map +1 -1
- package/lib/d3Force/forceInBox.js +75 -77
- package/lib/d3Force/forceInBox.js.map +1 -1
- package/lib/d3Force/index.d.ts +2 -2
- package/lib/d3Force/index.js +196 -222
- package/lib/d3Force/index.js.map +1 -1
- package/lib/dagre.d.ts +13 -24
- package/lib/dagre.js +57 -542
- package/lib/dagre.js.map +1 -1
- package/lib/exports.d.ts +17 -0
- package/lib/exports.js +17 -0
- package/lib/exports.js.map +1 -0
- package/lib/force/forceNBody.js +42 -45
- package/lib/force/forceNBody.js.map +1 -1
- package/lib/force/index.d.ts +1 -1
- package/lib/force/index.js +282 -309
- package/lib/force/index.js.map +1 -1
- package/lib/force/types.d.ts +5 -5
- package/lib/forceAtlas2/body.d.ts +1 -1
- package/lib/forceAtlas2/body.js +29 -31
- package/lib/forceAtlas2/body.js.map +1 -1
- package/lib/forceAtlas2/index.d.ts +1 -1
- package/lib/forceAtlas2/index.js +206 -218
- package/lib/forceAtlas2/index.js.map +1 -1
- package/lib/forceAtlas2/quad.d.ts +2 -2
- package/lib/forceAtlas2/quad.js +40 -42
- package/lib/forceAtlas2/quad.js.map +1 -1
- package/lib/forceAtlas2/quadTree.js +16 -17
- package/lib/forceAtlas2/quadTree.js.map +1 -1
- package/lib/fruchterman.d.ts +1 -1
- package/lib/fruchterman.js +185 -205
- package/lib/fruchterman.js.map +1 -1
- package/lib/grid.d.ts +1 -1
- package/lib/grid.js +197 -207
- package/lib/grid.js.map +1 -1
- package/lib/index.d.ts +1 -15
- package/lib/index.js +1 -15
- package/lib/index.js.map +1 -1
- package/lib/mds.d.ts +1 -1
- package/lib/mds.js +68 -78
- package/lib/mds.js.map +1 -1
- package/lib/radial/index.d.ts +1 -1
- package/lib/radial/index.js +177 -184
- package/lib/radial/index.js.map +1 -1
- package/lib/radial/mds.d.ts +1 -1
- package/lib/radial/mds.js +15 -13
- package/lib/radial/mds.js.map +1 -1
- package/lib/radial/radial-nonoverlap-force.d.ts +2 -2
- package/lib/radial/radial-nonoverlap-force.js +36 -37
- package/lib/radial/radial-nonoverlap-force.js.map +1 -1
- package/lib/random.d.ts +1 -1
- package/lib/random.js +53 -66
- package/lib/random.js.map +1 -1
- package/lib/registry.d.ts +2 -2
- package/lib/registry.js +3 -1
- package/lib/registry.js.map +1 -1
- package/lib/supervisor.d.ts +2 -3
- package/lib/supervisor.js +57 -56
- package/lib/supervisor.js.map +1 -1
- package/lib/types.d.ts +20 -75
- package/lib/types.js.map +1 -1
- package/lib/util/array.js +1 -1
- package/lib/util/array.js.map +1 -1
- package/lib/util/common.d.ts +1 -1
- package/lib/util/common.js +7 -8
- package/lib/util/common.js.map +1 -1
- package/lib/util/function.js +23 -25
- package/lib/util/function.js.map +1 -1
- package/lib/util/index.d.ts +0 -2
- package/lib/util/index.js +0 -2
- package/lib/util/index.js.map +1 -1
- package/lib/util/math.d.ts +1 -26
- package/lib/util/math.js +41 -149
- package/lib/util/math.js.map +1 -1
- package/lib/util/object.d.ts +1 -1
- package/lib/util/object.js +13 -13
- package/lib/util/object.js.map +1 -1
- package/lib/util/size.d.ts +3 -0
- package/lib/util/size.js +12 -0
- package/lib/util/size.js.map +1 -0
- package/lib/worker.js +30 -31
- package/lib/worker.js.map +1 -1
- package/package.json +9 -5
- package/dist/aa1bb0ccc06b11cf79c1.worker.js +0 -2
- package/dist/aa1bb0ccc06b11cf79c1.worker.js.map +0 -1
- package/lib/dagre/acyclic.js +0 -62
- package/lib/dagre/acyclic.js.map +0 -1
- package/lib/dagre/add-border-segments.js.map +0 -1
- package/lib/dagre/coordinate-system.js +0 -65
- package/lib/dagre/coordinate-system.js.map +0 -1
- package/lib/dagre/data/list.js.map +0 -1
- package/lib/dagre/greedy-fas.js +0 -147
- package/lib/dagre/greedy-fas.js.map +0 -1
- package/lib/dagre/layout.js.map +0 -1
- package/lib/dagre/nesting-graph.js.map +0 -1
- package/lib/dagre/normalize.js.map +0 -1
- package/lib/dagre/order/add-subgraph-constraints.js.map +0 -1
- package/lib/dagre/order/barycenter.js.map +0 -1
- package/lib/dagre/order/build-layer-graph.js.map +0 -1
- package/lib/dagre/order/cross-count.d.ts +0 -3
- package/lib/dagre/order/cross-count.js.map +0 -1
- package/lib/dagre/order/index.js.map +0 -1
- package/lib/dagre/order/init-data-order.js.map +0 -1
- package/lib/dagre/order/init-order.js +0 -50
- package/lib/dagre/order/init-order.js.map +0 -1
- package/lib/dagre/order/resolve-conflicts.js.map +0 -1
- package/lib/dagre/order/sort-subgraph.js.map +0 -1
- package/lib/dagre/order/sort.js.map +0 -1
- package/lib/dagre/parent-dummy-chains.js.map +0 -1
- package/lib/dagre/position/bk.js.map +0 -1
- package/lib/dagre/position/index.js +0 -54
- package/lib/dagre/position/index.js.map +0 -1
- package/lib/dagre/rank/feasible-tree.js.map +0 -1
- package/lib/dagre/rank/index.d.ts +0 -2
- package/lib/dagre/rank/index.js.map +0 -1
- package/lib/dagre/rank/network-simplex.js.map +0 -1
- package/lib/dagre/rank/util.js.map +0 -1
- package/lib/dagre/util.js.map +0 -1
- package/lib/util/gpu.d.ts +0 -45
- package/lib/util/gpu.js +0 -214
- package/lib/util/gpu.js.map +0 -1
- package/lib/util/number.d.ts +0 -1
- package/lib/util/number.js +0 -5
- package/lib/util/number.js.map +0 -1
- package/lib/util/string.d.ts +0 -1
- package/lib/util/string.js +0 -15
- package/lib/util/string.js.map +0 -1
- /package/lib/{dagre → antv-dagre}/add-border-segments.d.ts +0 -0
- /package/lib/{dagre → antv-dagre}/nesting-graph.d.ts +0 -0
- /package/lib/{dagre → antv-dagre}/order/add-subgraph-constraints.d.ts +0 -0
- /package/lib/{dagre → antv-dagre}/order/build-layer-graph.d.ts +0 -0
- /package/lib/{dagre → antv-dagre}/order/init-data-order.d.ts +0 -0
- /package/lib/{dagre → antv-dagre}/order/init-order.d.ts +0 -0
- /package/lib/{dagre → antv-dagre}/order/sort-subgraph.d.ts +0 -0
- /package/lib/{dagre → antv-dagre}/parent-dummy-chains.d.ts +0 -0
package/lib/force/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
2
|
import { Graph as IGraph } from '@antv/graphlib';
|
|
3
3
|
import { isFunction, isNumber, isObject } from '@antv/util';
|
|
4
4
|
import { formatNumberFn, isArray } from '../util';
|
|
5
5
|
import { forceNBody } from './forceNBody';
|
|
6
|
-
|
|
6
|
+
const DEFAULTS_LAYOUT_OPTIONS = {
|
|
7
7
|
dimensions: 2,
|
|
8
8
|
maxIteration: 500,
|
|
9
9
|
gravity: 10,
|
|
@@ -35,9 +35,8 @@ var DEFAULTS_LAYOUT_OPTIONS = {
|
|
|
35
35
|
* // If you want to assign the positions directly to the nodes, use assign method.
|
|
36
36
|
* await layout.assign(graph, { center: [100, 100] });
|
|
37
37
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (options === void 0) { options = {}; }
|
|
38
|
+
export class ForceLayout {
|
|
39
|
+
constructor(options = {}) {
|
|
41
40
|
this.options = options;
|
|
42
41
|
this.id = 'force';
|
|
43
42
|
/**
|
|
@@ -49,162 +48,148 @@ var ForceLayout = /** @class */ (function () {
|
|
|
49
48
|
*/
|
|
50
49
|
this.judgingDistance = 0;
|
|
51
50
|
this.running = false;
|
|
52
|
-
this.options =
|
|
51
|
+
this.options = Object.assign(Object.assign({}, DEFAULTS_LAYOUT_OPTIONS), options);
|
|
53
52
|
}
|
|
54
53
|
/**
|
|
55
54
|
* Return the positions of nodes and edges(if needed).
|
|
56
55
|
*/
|
|
57
|
-
|
|
58
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
59
|
-
return
|
|
60
|
-
return [2 /*return*/, this.genericForceLayout(false, graph, options)];
|
|
61
|
-
});
|
|
56
|
+
execute(graph, options) {
|
|
57
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
+
return this.genericForceLayout(false, graph, options);
|
|
62
59
|
});
|
|
63
|
-
}
|
|
60
|
+
}
|
|
64
61
|
/**
|
|
65
62
|
* To directly assign the positions to the nodes.
|
|
66
63
|
*/
|
|
67
|
-
|
|
68
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
69
|
-
|
|
70
|
-
this.genericForceLayout(true, graph, options);
|
|
71
|
-
return [2 /*return*/];
|
|
72
|
-
});
|
|
64
|
+
assign(graph, options) {
|
|
65
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
66
|
+
this.genericForceLayout(true, graph, options);
|
|
73
67
|
});
|
|
74
|
-
}
|
|
68
|
+
}
|
|
75
69
|
/**
|
|
76
70
|
* Stop simulation immediately.
|
|
77
71
|
*/
|
|
78
|
-
|
|
72
|
+
stop() {
|
|
79
73
|
if (this.timeInterval && typeof window !== 'undefined') {
|
|
80
74
|
window.clearInterval(this.timeInterval);
|
|
81
75
|
}
|
|
82
76
|
this.running = false;
|
|
83
|
-
}
|
|
77
|
+
}
|
|
84
78
|
/**
|
|
85
79
|
* Manually steps the simulation by the specified number of iterations.
|
|
86
80
|
* @see https://github.com/d3/d3-force#simulation_tick
|
|
87
81
|
*/
|
|
88
|
-
|
|
89
|
-
var _this = this;
|
|
90
|
-
if (iterations === void 0) { iterations = this.options.maxIteration || 1; }
|
|
82
|
+
tick(iterations = this.options.maxIteration || 1) {
|
|
91
83
|
if (this.lastResult) {
|
|
92
84
|
return this.lastResult;
|
|
93
85
|
}
|
|
94
|
-
for (
|
|
86
|
+
for (let i = 0; (this.judgingDistance > this.lastOptions.minMovement || i < 1) &&
|
|
95
87
|
i < iterations; i++) {
|
|
96
88
|
this.runOneStep(this.lastCalcGraph, this.lastGraph, i, this.lastVelMap, this.lastOptions);
|
|
97
89
|
this.updatePosition(this.lastGraph, this.lastCalcGraph, this.lastVelMap, this.lastOptions);
|
|
98
90
|
}
|
|
99
|
-
|
|
91
|
+
const result = {
|
|
100
92
|
nodes: this.lastLayoutNodes,
|
|
101
93
|
edges: this.lastLayoutEdges,
|
|
102
94
|
};
|
|
103
95
|
if (this.lastAssign) {
|
|
104
|
-
result.nodes.forEach(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
});
|
|
110
|
-
});
|
|
96
|
+
result.nodes.forEach((node) => this.lastGraph.mergeNodeData(node.id, {
|
|
97
|
+
x: node.data.x,
|
|
98
|
+
y: node.data.y,
|
|
99
|
+
z: this.options.dimensions === 3 ? node.data.z : undefined,
|
|
100
|
+
}));
|
|
111
101
|
}
|
|
112
102
|
return result;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
velMap = {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
}, 0);
|
|
194
|
-
_this.running = true;
|
|
195
|
-
})];
|
|
103
|
+
}
|
|
104
|
+
genericForceLayout(assign, graph, options) {
|
|
105
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
106
|
+
const mergedOptions = Object.assign(Object.assign({}, this.options), options);
|
|
107
|
+
const nodes = graph.getAllNodes();
|
|
108
|
+
const edges = graph.getAllEdges();
|
|
109
|
+
const formattedOptions = this.formatOptions(mergedOptions, graph);
|
|
110
|
+
const { dimensions, width, height, nodeSize, getMass, nodeStrength, edgeStrength, linkDistance, } = formattedOptions;
|
|
111
|
+
// clones the original data and attaches calculation attributes for this layout algorithm
|
|
112
|
+
const layoutNodes = nodes.map((node, i) => {
|
|
113
|
+
return Object.assign(Object.assign({}, node), { data: Object.assign(Object.assign({}, node.data), {
|
|
114
|
+
// ...randomDistribution(node, dimensions, 30, i),
|
|
115
|
+
x: isNumber(node.data.x) ? node.data.x : Math.random() * width, y: isNumber(node.data.y) ? node.data.y : Math.random() * height, z: isNumber(node.data.z)
|
|
116
|
+
? node.data.z
|
|
117
|
+
: Math.random() * Math.sqrt(width * height), size: nodeSize(node) || 30, mass: getMass(node), nodeStrength: nodeStrength(node) }) });
|
|
118
|
+
});
|
|
119
|
+
const layoutEdges = edges.map((edge) => (Object.assign(Object.assign({}, edge), { data: Object.assign(Object.assign({}, edge.data), { edgeStrength: edgeStrength(edge), linkDistance: linkDistance(edge, graph.getNode(edge.source), graph.getNode(edge.target)) }) })));
|
|
120
|
+
if (!(nodes === null || nodes === void 0 ? void 0 : nodes.length)) {
|
|
121
|
+
this.lastResult = { nodes: [], edges };
|
|
122
|
+
return { nodes: [], edges };
|
|
123
|
+
}
|
|
124
|
+
const velMap = {};
|
|
125
|
+
nodes.forEach((node, i) => {
|
|
126
|
+
velMap[node.id] = {
|
|
127
|
+
x: 0,
|
|
128
|
+
y: 0,
|
|
129
|
+
z: 0,
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
const calcGraph = new IGraph({
|
|
133
|
+
nodes: layoutNodes,
|
|
134
|
+
edges: layoutEdges,
|
|
135
|
+
});
|
|
136
|
+
this.formatCentripetal(formattedOptions, calcGraph);
|
|
137
|
+
const { maxIteration, minMovement, onTick } = formattedOptions;
|
|
138
|
+
// Use them later in `tick`.
|
|
139
|
+
this.lastLayoutNodes = layoutNodes;
|
|
140
|
+
this.lastLayoutEdges = layoutEdges;
|
|
141
|
+
this.lastAssign = assign;
|
|
142
|
+
this.lastGraph = graph;
|
|
143
|
+
this.lastCalcGraph = calcGraph;
|
|
144
|
+
this.lastOptions = formattedOptions;
|
|
145
|
+
this.lastVelMap = velMap;
|
|
146
|
+
if (typeof window === 'undefined')
|
|
147
|
+
return;
|
|
148
|
+
let iter = 0;
|
|
149
|
+
return new Promise((resolve) => {
|
|
150
|
+
// interval for render the result after each iteration
|
|
151
|
+
this.timeInterval = window.setInterval(() => {
|
|
152
|
+
if (!nodes || !this.running) {
|
|
153
|
+
resolve({
|
|
154
|
+
nodes: formatOutNodes(graph, layoutNodes),
|
|
155
|
+
edges,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
this.runOneStep(calcGraph, graph, iter, velMap, formattedOptions);
|
|
159
|
+
this.updatePosition(graph, calcGraph, velMap, formattedOptions);
|
|
160
|
+
if (assign) {
|
|
161
|
+
layoutNodes.forEach((node) => graph.mergeNodeData(node.id, {
|
|
162
|
+
x: node.data.x,
|
|
163
|
+
y: node.data.y,
|
|
164
|
+
z: dimensions === 3 ? node.data.z : undefined,
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
onTick === null || onTick === void 0 ? void 0 : onTick({
|
|
168
|
+
nodes: formatOutNodes(graph, layoutNodes),
|
|
169
|
+
edges,
|
|
170
|
+
});
|
|
171
|
+
iter++;
|
|
172
|
+
if (iter >= maxIteration || this.judgingDistance < minMovement) {
|
|
173
|
+
window.clearInterval(this.timeInterval);
|
|
174
|
+
resolve({
|
|
175
|
+
nodes: formatOutNodes(graph, layoutNodes),
|
|
176
|
+
edges,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}, 0);
|
|
180
|
+
this.running = true;
|
|
196
181
|
});
|
|
197
182
|
});
|
|
198
|
-
}
|
|
183
|
+
}
|
|
199
184
|
/**
|
|
200
185
|
* Format merged layout options.
|
|
201
186
|
* @param options merged layout options
|
|
202
187
|
* @param graph original graph
|
|
203
188
|
* @returns
|
|
204
189
|
*/
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
190
|
+
formatOptions(options, graph) {
|
|
191
|
+
const formattedOptions = Object.assign({}, options);
|
|
192
|
+
const { width: propsWidth, height: propsHeight, getMass, nodeSize, } = options;
|
|
208
193
|
// === formating width, height, and center =====
|
|
209
194
|
formattedOptions.width =
|
|
210
195
|
!propsWidth && typeof window !== 'undefined'
|
|
@@ -222,20 +207,20 @@ var ForceLayout = /** @class */ (function () {
|
|
|
222
207
|
}
|
|
223
208
|
// === formating node mass =====
|
|
224
209
|
if (!getMass) {
|
|
225
|
-
formattedOptions.getMass =
|
|
226
|
-
|
|
210
|
+
formattedOptions.getMass = (d) => {
|
|
211
|
+
let massWeight = 1;
|
|
227
212
|
if (isNumber(d === null || d === void 0 ? void 0 : d.data.mass))
|
|
228
213
|
massWeight = d === null || d === void 0 ? void 0 : d.data.mass;
|
|
229
|
-
|
|
214
|
+
const degree = graph.getDegree(d.id, 'both');
|
|
230
215
|
return !degree || degree < 5 ? massWeight : degree * 5 * massWeight;
|
|
231
216
|
};
|
|
232
217
|
}
|
|
233
218
|
// === formating node size =====
|
|
234
|
-
|
|
235
|
-
|
|
219
|
+
const nodeSpacingFunc = formatNumberFn(0, options.nodeSpacing);
|
|
220
|
+
let nodeSizeFn;
|
|
236
221
|
if (!nodeSize) {
|
|
237
|
-
nodeSizeFn =
|
|
238
|
-
|
|
222
|
+
nodeSizeFn = (d) => {
|
|
223
|
+
const { size } = (d === null || d === void 0 ? void 0 : d.data) || {};
|
|
239
224
|
if (size) {
|
|
240
225
|
if (isArray(size)) {
|
|
241
226
|
return Math.max(size[0], size[1]) + nodeSpacingFunc(d);
|
|
@@ -249,22 +234,22 @@ var ForceLayout = /** @class */ (function () {
|
|
|
249
234
|
};
|
|
250
235
|
}
|
|
251
236
|
else if (isFunction(nodeSize)) {
|
|
252
|
-
nodeSizeFn =
|
|
237
|
+
nodeSizeFn = (d) => nodeSize(d) + nodeSpacingFunc(d);
|
|
253
238
|
}
|
|
254
239
|
else if (isArray(nodeSize)) {
|
|
255
|
-
nodeSizeFn =
|
|
256
|
-
|
|
240
|
+
nodeSizeFn = (d) => {
|
|
241
|
+
const nodeSizeArr = nodeSize;
|
|
257
242
|
return Math.max(nodeSizeArr[0], nodeSizeArr[1]) + nodeSpacingFunc(d);
|
|
258
243
|
};
|
|
259
244
|
}
|
|
260
245
|
else {
|
|
261
|
-
nodeSizeFn =
|
|
246
|
+
nodeSizeFn = (d) => nodeSize + nodeSpacingFunc(d);
|
|
262
247
|
}
|
|
263
248
|
formattedOptions.nodeSize = nodeSizeFn;
|
|
264
249
|
// === formating node / edge strengths =====
|
|
265
|
-
|
|
250
|
+
const linkDistanceFn = options.linkDistance
|
|
266
251
|
? formatNumberFn(1, options.linkDistance)
|
|
267
|
-
:
|
|
252
|
+
: (edge) => {
|
|
268
253
|
return (1 +
|
|
269
254
|
formattedOptions.nodeSize(graph.getNode(edge.source)) +
|
|
270
255
|
formattedOptions.nodeSize(graph.getNode(edge.target)));
|
|
@@ -273,22 +258,22 @@ var ForceLayout = /** @class */ (function () {
|
|
|
273
258
|
formattedOptions.nodeStrength = formatNumberFn(1, options.nodeStrength);
|
|
274
259
|
formattedOptions.edgeStrength = formatNumberFn(1, options.edgeStrength);
|
|
275
260
|
return formattedOptions;
|
|
276
|
-
}
|
|
261
|
+
}
|
|
277
262
|
/**
|
|
278
263
|
* Format centripetalOption in the option.
|
|
279
264
|
* @param options merged layout options
|
|
280
265
|
* @param calcGraph calculation graph
|
|
281
266
|
*/
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
267
|
+
formatCentripetal(options, calcGraph) {
|
|
268
|
+
const { dimensions, centripetalOptions, center, clusterNodeStrength, leafCluster, clustering, nodeClusterBy, } = options;
|
|
269
|
+
const calcNodes = calcGraph.getAllNodes();
|
|
285
270
|
// === formating centripetalOptions =====
|
|
286
|
-
|
|
271
|
+
const basicCentripetal = centripetalOptions || {
|
|
287
272
|
leaf: 2,
|
|
288
273
|
single: 2,
|
|
289
274
|
others: 1,
|
|
290
275
|
// eslint-disable-next-line
|
|
291
|
-
center:
|
|
276
|
+
center: (n) => {
|
|
292
277
|
return {
|
|
293
278
|
x: center[0],
|
|
294
279
|
y: center[1],
|
|
@@ -297,22 +282,20 @@ var ForceLayout = /** @class */ (function () {
|
|
|
297
282
|
},
|
|
298
283
|
};
|
|
299
284
|
if (typeof clusterNodeStrength !== 'function') {
|
|
300
|
-
options.clusterNodeStrength =
|
|
301
|
-
return clusterNodeStrength;
|
|
302
|
-
};
|
|
285
|
+
options.clusterNodeStrength = (node) => clusterNodeStrength;
|
|
303
286
|
}
|
|
304
|
-
|
|
305
|
-
|
|
287
|
+
let sameTypeLeafMap;
|
|
288
|
+
let clusters;
|
|
306
289
|
if (leafCluster && nodeClusterBy) {
|
|
307
290
|
sameTypeLeafMap = getSameTypeLeafMap(calcGraph, nodeClusterBy);
|
|
308
291
|
clusters =
|
|
309
|
-
Array.from(new Set(calcNodes === null || calcNodes === void 0 ? void 0 : calcNodes.map(
|
|
292
|
+
Array.from(new Set(calcNodes === null || calcNodes === void 0 ? void 0 : calcNodes.map((node) => node.data[nodeClusterBy]))) || [];
|
|
310
293
|
// @ts-ignore
|
|
311
294
|
options.centripetalOptions = Object.assign(basicCentripetal, {
|
|
312
295
|
single: 100,
|
|
313
|
-
leaf:
|
|
296
|
+
leaf: (node) => {
|
|
314
297
|
// 找出与它关联的边的起点或终点出发的所有一度节点中同类型的叶子节点
|
|
315
|
-
|
|
298
|
+
const { siblingLeaves, sameTypeLeaves } = sameTypeLeafMap[node.id] || {};
|
|
316
299
|
// 如果都是同一类型或者每种类型只有1个,则施加默认向心力
|
|
317
300
|
if ((sameTypeLeaves === null || sameTypeLeaves === void 0 ? void 0 : sameTypeLeaves.length) === (siblingLeaves === null || siblingLeaves === void 0 ? void 0 : siblingLeaves.length) ||
|
|
318
301
|
(clusters === null || clusters === void 0 ? void 0 : clusters.length) === 1) {
|
|
@@ -321,8 +304,8 @@ var ForceLayout = /** @class */ (function () {
|
|
|
321
304
|
return options.clusterNodeStrength(node);
|
|
322
305
|
},
|
|
323
306
|
others: 1,
|
|
324
|
-
center:
|
|
325
|
-
|
|
307
|
+
center: (node) => {
|
|
308
|
+
const degree = calcGraph.getDegree(node.id, 'both');
|
|
326
309
|
// 孤点默认给1个远离的中心点
|
|
327
310
|
if (!degree) {
|
|
328
311
|
return {
|
|
@@ -331,11 +314,11 @@ var ForceLayout = /** @class */ (function () {
|
|
|
331
314
|
z: 0,
|
|
332
315
|
};
|
|
333
316
|
}
|
|
334
|
-
|
|
317
|
+
let centerPos;
|
|
335
318
|
if (degree === 1) {
|
|
336
319
|
// 如果为叶子节点
|
|
337
320
|
// 找出与它关联的边的起点出发的所有一度节点中同类型的叶子节点
|
|
338
|
-
|
|
321
|
+
const { sameTypeLeaves = [] } = sameTypeLeafMap[node.id] || {};
|
|
339
322
|
if (sameTypeLeaves.length === 1) {
|
|
340
323
|
// 如果同类型的叶子节点只有1个,中心位置为undefined
|
|
341
324
|
centerPos = undefined;
|
|
@@ -361,24 +344,24 @@ var ForceLayout = /** @class */ (function () {
|
|
|
361
344
|
sameTypeLeafMap = getSameTypeLeafMap(calcGraph, nodeClusterBy);
|
|
362
345
|
}
|
|
363
346
|
if (!clusters) {
|
|
364
|
-
clusters = Array.from(new Set(calcNodes.map(
|
|
347
|
+
clusters = Array.from(new Set(calcNodes.map((node) => node.data[nodeClusterBy])));
|
|
365
348
|
}
|
|
366
|
-
clusters = clusters.filter(
|
|
367
|
-
|
|
368
|
-
clusters.forEach(
|
|
369
|
-
|
|
370
|
-
.filter(
|
|
371
|
-
.map(
|
|
349
|
+
clusters = clusters.filter((item) => item !== undefined);
|
|
350
|
+
const centerInfo = {};
|
|
351
|
+
clusters.forEach((cluster) => {
|
|
352
|
+
const sameTypeNodes = calcNodes
|
|
353
|
+
.filter((node) => node.data[nodeClusterBy] === cluster)
|
|
354
|
+
.map((node) => calcGraph.getNode(node.id));
|
|
372
355
|
// 找出同类型节点平均位置节点的距离最近的节点作为中心节点
|
|
373
|
-
|
|
356
|
+
centerInfo[cluster] = getAvgNodePosition(sameTypeNodes);
|
|
374
357
|
});
|
|
375
358
|
options.centripetalOptions = Object.assign(basicCentripetal, {
|
|
376
|
-
single:
|
|
377
|
-
leaf:
|
|
378
|
-
others:
|
|
379
|
-
center:
|
|
359
|
+
single: (node) => options.clusterNodeStrength(node),
|
|
360
|
+
leaf: (node) => options.clusterNodeStrength(node),
|
|
361
|
+
others: (node) => options.clusterNodeStrength(node),
|
|
362
|
+
center: (node) => {
|
|
380
363
|
// 找出同类型节点平均位置节点的距离最近的节点作为中心节点
|
|
381
|
-
|
|
364
|
+
const centerPos = centerInfo[node.data[nodeClusterBy]];
|
|
382
365
|
return {
|
|
383
366
|
x: centerPos === null || centerPos === void 0 ? void 0 : centerPos.x,
|
|
384
367
|
y: centerPos === null || centerPos === void 0 ? void 0 : centerPos.y,
|
|
@@ -387,17 +370,17 @@ var ForceLayout = /** @class */ (function () {
|
|
|
387
370
|
},
|
|
388
371
|
});
|
|
389
372
|
}
|
|
390
|
-
|
|
373
|
+
const { leaf, single, others } = options.centripetalOptions || {};
|
|
391
374
|
if (leaf && typeof leaf !== 'function') {
|
|
392
|
-
options.centripetalOptions.leaf =
|
|
375
|
+
options.centripetalOptions.leaf = () => leaf;
|
|
393
376
|
}
|
|
394
377
|
if (single && typeof single !== 'function') {
|
|
395
|
-
options.centripetalOptions.single =
|
|
378
|
+
options.centripetalOptions.single = () => single;
|
|
396
379
|
}
|
|
397
380
|
if (others && typeof others !== 'function') {
|
|
398
|
-
options.centripetalOptions.others =
|
|
381
|
+
options.centripetalOptions.others = () => others;
|
|
399
382
|
}
|
|
400
|
-
}
|
|
383
|
+
}
|
|
401
384
|
/**
|
|
402
385
|
* One iteration.
|
|
403
386
|
* @param calcGraph calculation graph
|
|
@@ -407,13 +390,13 @@ var ForceLayout = /** @class */ (function () {
|
|
|
407
390
|
* @param options formatted layout options
|
|
408
391
|
* @returns
|
|
409
392
|
*/
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
393
|
+
runOneStep(calcGraph, graph, iter, velMap, options) {
|
|
394
|
+
const accMap = {};
|
|
395
|
+
const calcNodes = calcGraph.getAllNodes();
|
|
396
|
+
const calcEdges = calcGraph.getAllEdges();
|
|
414
397
|
if (!(calcNodes === null || calcNodes === void 0 ? void 0 : calcNodes.length))
|
|
415
398
|
return;
|
|
416
|
-
|
|
399
|
+
const { monitor } = options;
|
|
417
400
|
this.calRepulsive(calcGraph, accMap, options);
|
|
418
401
|
if (calcEdges)
|
|
419
402
|
this.calAttractive(calcGraph, accMap, options);
|
|
@@ -421,62 +404,61 @@ var ForceLayout = /** @class */ (function () {
|
|
|
421
404
|
this.updateVelocity(calcGraph, accMap, velMap, options);
|
|
422
405
|
/** 如果需要监控信息,则提供给用户 */
|
|
423
406
|
if (monitor) {
|
|
424
|
-
|
|
407
|
+
const energy = this.calTotalEnergy(accMap, calcNodes);
|
|
425
408
|
monitor({
|
|
426
|
-
energy
|
|
409
|
+
energy,
|
|
427
410
|
nodes: graph.getAllNodes(),
|
|
428
411
|
edges: graph.getAllEdges(),
|
|
429
412
|
iterations: iter,
|
|
430
413
|
});
|
|
431
414
|
}
|
|
432
|
-
}
|
|
415
|
+
}
|
|
433
416
|
/**
|
|
434
417
|
* Calculate graph energy for monitoring convergence.
|
|
435
418
|
* @param accMap acceleration map
|
|
436
419
|
* @param nodes calculation nodes
|
|
437
420
|
* @returns energy
|
|
438
421
|
*/
|
|
439
|
-
|
|
440
|
-
var _this = this;
|
|
422
|
+
calTotalEnergy(accMap, nodes) {
|
|
441
423
|
if (!(nodes === null || nodes === void 0 ? void 0 : nodes.length))
|
|
442
424
|
return 0;
|
|
443
|
-
|
|
444
|
-
nodes.forEach(
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
425
|
+
let energy = 0.0;
|
|
426
|
+
nodes.forEach((node, i) => {
|
|
427
|
+
const vx = accMap[node.id].x;
|
|
428
|
+
const vy = accMap[node.id].y;
|
|
429
|
+
const vz = this.options.dimensions === 3 ? accMap[node.id].z : 0;
|
|
430
|
+
const speed2 = vx * vx + vy * vy + vz * vz;
|
|
431
|
+
const { mass = 1 } = node.data;
|
|
450
432
|
energy += mass * speed2 * 0.5; // p = 1/2*(mv^2)
|
|
451
433
|
});
|
|
452
434
|
return energy;
|
|
453
|
-
}
|
|
435
|
+
}
|
|
454
436
|
/**
|
|
455
437
|
* Calculate the repulsive forces according to coulombs law.
|
|
456
438
|
* @param calcGraph calculation graph
|
|
457
439
|
* @param accMap acceleration map
|
|
458
440
|
* @param options formatted layout options
|
|
459
441
|
*/
|
|
460
|
-
|
|
461
|
-
|
|
442
|
+
calRepulsive(calcGraph, accMap, options) {
|
|
443
|
+
const { dimensions, factor, coulombDisScale } = options;
|
|
462
444
|
forceNBody(calcGraph, factor, coulombDisScale * coulombDisScale, accMap, dimensions);
|
|
463
|
-
}
|
|
445
|
+
}
|
|
464
446
|
/**
|
|
465
447
|
* Calculate the attractive forces according to hooks law.
|
|
466
448
|
* @param calcGraph calculation graph
|
|
467
449
|
* @param accMap acceleration map
|
|
468
450
|
*/
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
calcGraph.getAllEdges().forEach(
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
451
|
+
calAttractive(calcGraph, accMap, options) {
|
|
452
|
+
const { dimensions, nodeSize } = options;
|
|
453
|
+
calcGraph.getAllEdges().forEach((edge, i) => {
|
|
454
|
+
const { source, target } = edge;
|
|
455
|
+
const sourceNode = calcGraph.getNode(source);
|
|
456
|
+
const targetNode = calcGraph.getNode(target);
|
|
475
457
|
if (!sourceNode || !targetNode)
|
|
476
458
|
return;
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
459
|
+
let vecX = targetNode.data.x - sourceNode.data.x;
|
|
460
|
+
let vecY = targetNode.data.y - sourceNode.data.y;
|
|
461
|
+
let vecZ = dimensions === 3 ? targetNode.data.z - sourceNode.data.z : 0;
|
|
480
462
|
if (!vecX && !vecY) {
|
|
481
463
|
vecX = Math.random() * 0.01;
|
|
482
464
|
vecY = Math.random() * 0.01;
|
|
@@ -484,23 +466,23 @@ var ForceLayout = /** @class */ (function () {
|
|
|
484
466
|
vecZ = Math.random() * 0.01;
|
|
485
467
|
}
|
|
486
468
|
}
|
|
487
|
-
|
|
469
|
+
const vecLength = Math.sqrt(vecX * vecX + vecY * vecY + vecZ * vecZ);
|
|
488
470
|
if (vecLength < nodeSize(sourceNode) + nodeSize(targetNode))
|
|
489
471
|
return;
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
472
|
+
const direX = vecX / vecLength;
|
|
473
|
+
const direY = vecY / vecLength;
|
|
474
|
+
const direZ = vecZ / vecLength;
|
|
475
|
+
const { linkDistance = 200, edgeStrength = 200 } = edge.data || {};
|
|
476
|
+
const diff = linkDistance - vecLength;
|
|
477
|
+
const param = diff * edgeStrength;
|
|
478
|
+
const massSource = sourceNode.data.mass || 1;
|
|
479
|
+
const massTarget = targetNode.data.mass || 1;
|
|
498
480
|
// 质量占比越大,对另一端影响程度越大
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
481
|
+
const sourceMassRatio = 1 / massSource;
|
|
482
|
+
const targetMassRatio = 1 / massTarget;
|
|
483
|
+
const disX = direX * param;
|
|
484
|
+
const disY = direY * param;
|
|
485
|
+
const disZ = direZ * param;
|
|
504
486
|
accMap[source].x -= disX * sourceMassRatio;
|
|
505
487
|
accMap[source].y -= disY * sourceMassRatio;
|
|
506
488
|
accMap[source].z -= disZ * sourceMassRatio;
|
|
@@ -508,7 +490,7 @@ var ForceLayout = /** @class */ (function () {
|
|
|
508
490
|
accMap[target].y += disY * targetMassRatio;
|
|
509
491
|
accMap[target].z += disZ * targetMassRatio;
|
|
510
492
|
});
|
|
511
|
-
}
|
|
493
|
+
}
|
|
512
494
|
/**
|
|
513
495
|
* Calculate the gravity forces toward center.
|
|
514
496
|
* @param calcGraph calculation graph
|
|
@@ -516,28 +498,28 @@ var ForceLayout = /** @class */ (function () {
|
|
|
516
498
|
* @param accMap acceleration map
|
|
517
499
|
* @param options formatted layout options
|
|
518
500
|
*/
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
501
|
+
calGravity(calcGraph, graph, accMap, options) {
|
|
502
|
+
const { getCenter } = options;
|
|
503
|
+
const calcNodes = calcGraph.getAllNodes();
|
|
504
|
+
const nodes = graph.getAllNodes();
|
|
505
|
+
const edges = graph.getAllEdges();
|
|
506
|
+
const { width, height, center, gravity: defaultGravity, centripetalOptions, } = options;
|
|
525
507
|
if (!calcNodes)
|
|
526
508
|
return;
|
|
527
|
-
calcNodes.forEach(
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
509
|
+
calcNodes.forEach((calcNode) => {
|
|
510
|
+
const { id, data } = calcNode;
|
|
511
|
+
const { mass, x, y, z } = data;
|
|
512
|
+
const node = graph.getNode(id);
|
|
513
|
+
let vecX = 0;
|
|
514
|
+
let vecY = 0;
|
|
515
|
+
let vecZ = 0;
|
|
516
|
+
let gravity = defaultGravity;
|
|
517
|
+
const inDegree = calcGraph.getDegree(id, 'in');
|
|
518
|
+
const outDegree = calcGraph.getDegree(id, 'out');
|
|
519
|
+
const degree = calcGraph.getDegree(id, 'both');
|
|
520
|
+
const forceCenter = getCenter === null || getCenter === void 0 ? void 0 : getCenter(node, degree);
|
|
539
521
|
if (forceCenter) {
|
|
540
|
-
|
|
522
|
+
const [centerX, centerY, strength] = forceCenter;
|
|
541
523
|
vecX = x - centerX;
|
|
542
524
|
vecY = y - centerY;
|
|
543
525
|
gravity = strength;
|
|
@@ -553,18 +535,18 @@ var ForceLayout = /** @class */ (function () {
|
|
|
553
535
|
accMap[id].z -= (gravity * vecZ) / mass;
|
|
554
536
|
}
|
|
555
537
|
if (centripetalOptions) {
|
|
556
|
-
|
|
557
|
-
|
|
538
|
+
const { leaf, single, others, center: centriCenter, } = centripetalOptions;
|
|
539
|
+
const { x: centriX, y: centriY, z: centriZ, centerStrength, } = (centriCenter === null || centriCenter === void 0 ? void 0 : centriCenter(node, nodes, edges, width, height)) || {
|
|
558
540
|
x: 0,
|
|
559
541
|
y: 0,
|
|
560
542
|
z: 0,
|
|
561
543
|
centerStrength: 0,
|
|
562
|
-
}
|
|
544
|
+
};
|
|
563
545
|
if (!isNumber(centriX) || !isNumber(centriY))
|
|
564
546
|
return;
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
547
|
+
const vx = (x - centriX) / mass;
|
|
548
|
+
const vy = (y - centriY) / mass;
|
|
549
|
+
const vz = (z - centriZ) / mass;
|
|
568
550
|
if (centerStrength) {
|
|
569
551
|
accMap[id].x -= centerStrength * vx;
|
|
570
552
|
accMap[id].y -= centerStrength * vy;
|
|
@@ -572,7 +554,7 @@ var ForceLayout = /** @class */ (function () {
|
|
|
572
554
|
}
|
|
573
555
|
// 孤点
|
|
574
556
|
if (degree === 0) {
|
|
575
|
-
|
|
557
|
+
const singleStrength = single(node);
|
|
576
558
|
if (!singleStrength)
|
|
577
559
|
return;
|
|
578
560
|
accMap[id].x -= singleStrength * vx;
|
|
@@ -582,7 +564,7 @@ var ForceLayout = /** @class */ (function () {
|
|
|
582
564
|
}
|
|
583
565
|
// 没有出度或没有入度,都认为是叶子节点
|
|
584
566
|
if (inDegree === 0 || outDegree === 0) {
|
|
585
|
-
|
|
567
|
+
const leafStrength = leaf(node, nodes, edges);
|
|
586
568
|
if (!leafStrength)
|
|
587
569
|
return;
|
|
588
570
|
accMap[id].x -= leafStrength * vx;
|
|
@@ -591,7 +573,7 @@ var ForceLayout = /** @class */ (function () {
|
|
|
591
573
|
return;
|
|
592
574
|
}
|
|
593
575
|
/** others */
|
|
594
|
-
|
|
576
|
+
const othersStrength = others(node);
|
|
595
577
|
if (!othersStrength)
|
|
596
578
|
return;
|
|
597
579
|
accMap[id].x -= othersStrength * vx;
|
|
@@ -599,7 +581,7 @@ var ForceLayout = /** @class */ (function () {
|
|
|
599
581
|
accMap[id].z -= othersStrength * vz;
|
|
600
582
|
}
|
|
601
583
|
});
|
|
602
|
-
}
|
|
584
|
+
}
|
|
603
585
|
/**
|
|
604
586
|
* Update the velocities for nodes.
|
|
605
587
|
* @param calcGraph calculation graph
|
|
@@ -608,21 +590,21 @@ var ForceLayout = /** @class */ (function () {
|
|
|
608
590
|
* @param options formatted layout options
|
|
609
591
|
* @returns
|
|
610
592
|
*/
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
593
|
+
updateVelocity(calcGraph, accMap, velMap, options) {
|
|
594
|
+
const { damping, maxSpeed, interval, dimensions } = options;
|
|
595
|
+
const calcNodes = calcGraph.getAllNodes();
|
|
614
596
|
if (!(calcNodes === null || calcNodes === void 0 ? void 0 : calcNodes.length))
|
|
615
597
|
return;
|
|
616
|
-
calcNodes.forEach(
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
598
|
+
calcNodes.forEach((calcNode) => {
|
|
599
|
+
const { id } = calcNode;
|
|
600
|
+
let vx = (velMap[id].x + accMap[id].x * interval) * damping || 0.01;
|
|
601
|
+
let vy = (velMap[id].y + accMap[id].y * interval) * damping || 0.01;
|
|
602
|
+
let vz = dimensions === 3
|
|
621
603
|
? (velMap[id].z + accMap[id].z * interval) * damping || 0.01
|
|
622
604
|
: 0.0;
|
|
623
|
-
|
|
605
|
+
const vLength = Math.sqrt(vx * vx + vy * vy + vz * vz);
|
|
624
606
|
if (vLength > maxSpeed) {
|
|
625
|
-
|
|
607
|
+
const param2 = maxSpeed / vLength;
|
|
626
608
|
vx = param2 * vx;
|
|
627
609
|
vy = param2 * vy;
|
|
628
610
|
vz = param2 * vz;
|
|
@@ -633,7 +615,7 @@ var ForceLayout = /** @class */ (function () {
|
|
|
633
615
|
z: vz,
|
|
634
616
|
};
|
|
635
617
|
});
|
|
636
|
-
}
|
|
618
|
+
}
|
|
637
619
|
/**
|
|
638
620
|
* Update nodes' positions.
|
|
639
621
|
* @param graph origin graph
|
|
@@ -642,22 +624,21 @@ var ForceLayout = /** @class */ (function () {
|
|
|
642
624
|
* @param options formatted layou options
|
|
643
625
|
* @returns
|
|
644
626
|
*/
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
var calcNodes = calcGraph.getAllNodes();
|
|
627
|
+
updatePosition(graph, calcGraph, velMap, options) {
|
|
628
|
+
const { distanceThresholdMode, interval, dimensions } = options;
|
|
629
|
+
const calcNodes = calcGraph.getAllNodes();
|
|
649
630
|
if (!(calcNodes === null || calcNodes === void 0 ? void 0 : calcNodes.length)) {
|
|
650
631
|
this.judgingDistance = 0;
|
|
651
632
|
return;
|
|
652
633
|
}
|
|
653
|
-
|
|
634
|
+
let sum = 0;
|
|
654
635
|
if (distanceThresholdMode === 'max')
|
|
655
636
|
this.judgingDistance = -Infinity;
|
|
656
637
|
else if (distanceThresholdMode === 'min')
|
|
657
638
|
this.judgingDistance = Infinity;
|
|
658
|
-
calcNodes.forEach(
|
|
659
|
-
|
|
660
|
-
|
|
639
|
+
calcNodes.forEach((calcNode) => {
|
|
640
|
+
const { id } = calcNode;
|
|
641
|
+
const node = graph.getNode(id);
|
|
661
642
|
if (isNumber(node.data.fx) && isNumber(node.data.fy)) {
|
|
662
643
|
calcGraph.mergeNodeData(id, {
|
|
663
644
|
x: node.data.fx,
|
|
@@ -666,24 +647,24 @@ var ForceLayout = /** @class */ (function () {
|
|
|
666
647
|
});
|
|
667
648
|
return;
|
|
668
649
|
}
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
650
|
+
const distX = velMap[id].x * interval;
|
|
651
|
+
const distY = velMap[id].y * interval;
|
|
652
|
+
const distZ = dimensions === 3 ? velMap[id].z * interval : 0.0;
|
|
672
653
|
calcGraph.mergeNodeData(id, {
|
|
673
654
|
x: calcNode.data.x + distX,
|
|
674
655
|
y: calcNode.data.y + distY,
|
|
675
656
|
z: calcNode.data.z + distZ,
|
|
676
657
|
});
|
|
677
|
-
|
|
658
|
+
const distanceMagnitude = Math.sqrt(distX * distX + distY * distY + distZ * distZ);
|
|
678
659
|
switch (distanceThresholdMode) {
|
|
679
660
|
case 'max':
|
|
680
|
-
if (
|
|
681
|
-
|
|
661
|
+
if (this.judgingDistance < distanceMagnitude) {
|
|
662
|
+
this.judgingDistance = distanceMagnitude;
|
|
682
663
|
}
|
|
683
664
|
break;
|
|
684
665
|
case 'min':
|
|
685
|
-
if (
|
|
686
|
-
|
|
666
|
+
if (this.judgingDistance > distanceMagnitude) {
|
|
667
|
+
this.judgingDistance = distanceMagnitude;
|
|
687
668
|
}
|
|
688
669
|
break;
|
|
689
670
|
default:
|
|
@@ -694,23 +675,21 @@ var ForceLayout = /** @class */ (function () {
|
|
|
694
675
|
if (!distanceThresholdMode || distanceThresholdMode === 'mean') {
|
|
695
676
|
this.judgingDistance = sum / calcNodes.length;
|
|
696
677
|
}
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
}());
|
|
700
|
-
export { ForceLayout };
|
|
678
|
+
}
|
|
679
|
+
}
|
|
701
680
|
/**
|
|
702
681
|
* Group the leaf nodes according to nodeClusterBy field.
|
|
703
682
|
* @param calcGraph calculation graph
|
|
704
683
|
* @param nodeClusterBy the field name in node.data to ditinguish different node clusters
|
|
705
684
|
* @returns related same group leaf nodes for each leaf node
|
|
706
685
|
*/
|
|
707
|
-
|
|
708
|
-
|
|
686
|
+
const getSameTypeLeafMap = (calcGraph, nodeClusterBy) => {
|
|
687
|
+
const calcNodes = calcGraph.getAllNodes();
|
|
709
688
|
if (!(calcNodes === null || calcNodes === void 0 ? void 0 : calcNodes.length))
|
|
710
689
|
return {};
|
|
711
|
-
|
|
712
|
-
calcNodes.forEach(
|
|
713
|
-
|
|
690
|
+
const sameTypeLeafMap = {};
|
|
691
|
+
calcNodes.forEach((node, i) => {
|
|
692
|
+
const degree = calcGraph.getDegree(node.id, 'both');
|
|
714
693
|
if (degree === 1) {
|
|
715
694
|
sameTypeLeafMap[node.id] = getCoreNodeAndSiblingLeaves(calcGraph, 'leaf', node, nodeClusterBy);
|
|
716
695
|
}
|
|
@@ -725,12 +704,12 @@ var getSameTypeLeafMap = function (calcGraph, nodeClusterBy) {
|
|
|
725
704
|
* @param nodeClusterBy the field name in node.data to ditinguish different node clusters
|
|
726
705
|
* @returns coreNode, sibling leaf nodes, and grouped sibling leaf nodes
|
|
727
706
|
*/
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
707
|
+
const getCoreNodeAndSiblingLeaves = (calcGraph, type, node, nodeClusterBy) => {
|
|
708
|
+
const inDegree = calcGraph.getDegree(node.id, 'in');
|
|
709
|
+
const outDegree = calcGraph.getDegree(node.id, 'out');
|
|
731
710
|
// node is not a leaf, coreNode is itself, siblingLeaves is empty
|
|
732
|
-
|
|
733
|
-
|
|
711
|
+
let coreNode = node;
|
|
712
|
+
let siblingLeaves = [];
|
|
734
713
|
if (inDegree === 0) {
|
|
735
714
|
// node is a leaf node without out edges, its related(successor) node is coreNode, siblingLeaves is the neighbors of its related node
|
|
736
715
|
coreNode = calcGraph.getSuccessors(node.id)[0];
|
|
@@ -742,12 +721,10 @@ var getCoreNodeAndSiblingLeaves = function (calcGraph, type, node, nodeClusterBy
|
|
|
742
721
|
siblingLeaves = calcGraph.getNeighbors(coreNode.id);
|
|
743
722
|
}
|
|
744
723
|
// siblingLeaves are leaf nodes
|
|
745
|
-
siblingLeaves = siblingLeaves.filter(
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
}
|
|
749
|
-
var sameTypeLeaves = getSameTypeNodes(calcGraph, type, nodeClusterBy, node, siblingLeaves);
|
|
750
|
-
return { coreNode: coreNode, siblingLeaves: siblingLeaves, sameTypeLeaves: sameTypeLeaves };
|
|
724
|
+
siblingLeaves = siblingLeaves.filter((node) => calcGraph.getDegree(node.id, 'in') === 0 ||
|
|
725
|
+
calcGraph.getDegree(node.id, 'out') === 0);
|
|
726
|
+
const sameTypeLeaves = getSameTypeNodes(calcGraph, type, nodeClusterBy, node, siblingLeaves);
|
|
727
|
+
return { coreNode, siblingLeaves, sameTypeLeaves };
|
|
751
728
|
};
|
|
752
729
|
/**
|
|
753
730
|
* Find the same type (according to nodeClusterBy field) of node in relativeNodes.
|
|
@@ -758,15 +735,13 @@ var getCoreNodeAndSiblingLeaves = function (calcGraph, type, node, nodeClusterBy
|
|
|
758
735
|
* @param relativeNodes node's related ndoes to be filtered
|
|
759
736
|
* @returns related nodes that meet the filtering conditions
|
|
760
737
|
*/
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
738
|
+
const getSameTypeNodes = (calcGraph, type, nodeClusterBy, node, relativeNodes) => {
|
|
739
|
+
const typeName = node.data[nodeClusterBy] || '';
|
|
740
|
+
let sameTypeNodes = (relativeNodes === null || relativeNodes === void 0 ? void 0 : relativeNodes.filter((item) => item.data[nodeClusterBy] === typeName)) ||
|
|
764
741
|
[];
|
|
765
742
|
if (type === 'leaf') {
|
|
766
|
-
sameTypeNodes = sameTypeNodes.filter(
|
|
767
|
-
|
|
768
|
-
calcGraph.getDegree(item.id, 'out') === 0;
|
|
769
|
-
});
|
|
743
|
+
sameTypeNodes = sameTypeNodes.filter((item) => calcGraph.getDegree(item.id, 'in') === 0 ||
|
|
744
|
+
calcGraph.getDegree(item.id, 'out') === 0);
|
|
770
745
|
}
|
|
771
746
|
return sameTypeNodes;
|
|
772
747
|
};
|
|
@@ -775,15 +750,15 @@ var getSameTypeNodes = function (calcGraph, type, nodeClusterBy, node, relativeN
|
|
|
775
750
|
* @param nodes nodes set
|
|
776
751
|
* @returns average ppsition
|
|
777
752
|
*/
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
nodes.forEach(
|
|
781
|
-
|
|
753
|
+
const getAvgNodePosition = (nodes) => {
|
|
754
|
+
const totalNodes = { x: 0, y: 0 };
|
|
755
|
+
nodes.forEach((node) => {
|
|
756
|
+
const { x, y } = node.data;
|
|
782
757
|
totalNodes.x += x || 0;
|
|
783
758
|
totalNodes.y += y || 0;
|
|
784
759
|
});
|
|
785
760
|
// 获取均值向量
|
|
786
|
-
|
|
761
|
+
const length = nodes.length || 1;
|
|
787
762
|
return {
|
|
788
763
|
x: totalNodes.x / length,
|
|
789
764
|
y: totalNodes.y / length,
|
|
@@ -795,11 +770,9 @@ var getAvgNodePosition = function (nodes) {
|
|
|
795
770
|
* @param layoutNodes calculation nodes
|
|
796
771
|
* @returns output nodes
|
|
797
772
|
*/
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
});
|
|
804
|
-
};
|
|
773
|
+
const formatOutNodes = (graph, layoutNodes) => layoutNodes.map((calcNode) => {
|
|
774
|
+
const { id, data } = calcNode;
|
|
775
|
+
const node = graph.getNode(id);
|
|
776
|
+
return Object.assign(Object.assign({}, node), { data: Object.assign(Object.assign({}, node.data), { x: data.x, y: data.y, z: data.z }) });
|
|
777
|
+
});
|
|
805
778
|
//# sourceMappingURL=index.js.map
|