@antv/layout 0.2.5 → 0.3.0-beta.2

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.
Files changed (74) hide show
  1. package/dist/layout.min.js +1 -1
  2. package/dist/layout.min.js.map +1 -1
  3. package/es/layout/circular.js +4 -4
  4. package/es/layout/circular.js.map +1 -1
  5. package/es/layout/concentric.js +1 -1
  6. package/es/layout/concentric.js.map +1 -1
  7. package/es/layout/constants.js +1 -0
  8. package/es/layout/constants.js.map +1 -1
  9. package/es/layout/dagre.js +3 -3
  10. package/es/layout/dagre.js.map +1 -1
  11. package/es/layout/force2/ForceNBody.d.ts +7 -0
  12. package/es/layout/force2/ForceNBody.js +94 -0
  13. package/es/layout/force2/ForceNBody.js.map +1 -0
  14. package/es/layout/force2/index.d.ts +123 -0
  15. package/es/layout/force2/index.js +609 -0
  16. package/es/layout/force2/index.js.map +1 -0
  17. package/es/layout/gForce.js +2 -2
  18. package/es/layout/gForce.js.map +1 -1
  19. package/es/layout/gpu/gForce.js +1 -1
  20. package/es/layout/gpu/gForce.js.map +1 -1
  21. package/es/layout/grid.js +1 -1
  22. package/es/layout/grid.js.map +1 -1
  23. package/es/layout/index.d.ts +2 -1
  24. package/es/layout/index.js +2 -1
  25. package/es/layout/index.js.map +1 -1
  26. package/es/layout/layout.js +2 -0
  27. package/es/layout/layout.js.map +1 -1
  28. package/es/layout/types.d.ts +61 -0
  29. package/es/util/math.d.ts +21 -2
  30. package/es/util/math.js +111 -4
  31. package/es/util/math.js.map +1 -1
  32. package/lib/layout/circular.js +4 -4
  33. package/lib/layout/circular.js.map +1 -1
  34. package/lib/layout/concentric.js +1 -1
  35. package/lib/layout/concentric.js.map +1 -1
  36. package/lib/layout/constants.js +1 -0
  37. package/lib/layout/constants.js.map +1 -1
  38. package/lib/layout/dagre.js +4 -4
  39. package/lib/layout/dagre.js.map +1 -1
  40. package/lib/layout/force2/ForceNBody.d.ts +7 -0
  41. package/lib/layout/force2/ForceNBody.js +98 -0
  42. package/lib/layout/force2/ForceNBody.js.map +1 -0
  43. package/lib/layout/force2/index.d.ts +123 -0
  44. package/lib/layout/force2/index.js +644 -0
  45. package/lib/layout/force2/index.js.map +1 -0
  46. package/lib/layout/gForce.js +2 -2
  47. package/lib/layout/gForce.js.map +1 -1
  48. package/lib/layout/gpu/gForce.js +1 -1
  49. package/lib/layout/gpu/gForce.js.map +1 -1
  50. package/lib/layout/grid.js +1 -1
  51. package/lib/layout/grid.js.map +1 -1
  52. package/lib/layout/index.d.ts +2 -1
  53. package/lib/layout/index.js +3 -1
  54. package/lib/layout/index.js.map +1 -1
  55. package/lib/layout/layout.js +2 -0
  56. package/lib/layout/layout.js.map +1 -1
  57. package/lib/layout/types.d.ts +61 -0
  58. package/lib/util/math.d.ts +21 -2
  59. package/lib/util/math.js +116 -6
  60. package/lib/util/math.js.map +1 -1
  61. package/package.json +4 -2
  62. package/src/layout/circular.ts +7 -6
  63. package/src/layout/concentric.ts +1 -1
  64. package/src/layout/constants.ts +1 -0
  65. package/src/layout/dagre.ts +1 -1
  66. package/src/layout/force2/ForceNBody.ts +128 -0
  67. package/src/layout/force2/index.ts +743 -0
  68. package/src/layout/gForce.ts +7 -6
  69. package/src/layout/gpu/gForce.ts +4 -3
  70. package/src/layout/grid.ts +1 -1
  71. package/src/layout/index.ts +2 -0
  72. package/src/layout/layout.ts +2 -0
  73. package/src/layout/types.ts +67 -0
  74. package/src/util/math.ts +122 -6
@@ -0,0 +1,644 @@
1
+ "use strict";
2
+ /**
3
+ * @fileOverview fruchterman layout
4
+ * @author shiwu.wyy@antfin.com
5
+ */
6
+ var __extends = (this && this.__extends) || (function () {
7
+ var extendStatics = function (d, b) {
8
+ extendStatics = Object.setPrototypeOf ||
9
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
10
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
11
+ return extendStatics(d, b);
12
+ };
13
+ return function (d, b) {
14
+ if (typeof b !== "function" && b !== null)
15
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
16
+ extendStatics(d, b);
17
+ function __() { this.constructor = d; }
18
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
19
+ };
20
+ })();
21
+ var __assign = (this && this.__assign) || function () {
22
+ __assign = Object.assign || function(t) {
23
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
24
+ s = arguments[i];
25
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
26
+ t[p] = s[p];
27
+ }
28
+ return t;
29
+ };
30
+ return __assign.apply(this, arguments);
31
+ };
32
+ Object.defineProperty(exports, "__esModule", { value: true });
33
+ exports.Force2Layout = void 0;
34
+ var base_1 = require("../base");
35
+ var util_1 = require("../../util");
36
+ var ForceNBody_1 = require("./ForceNBody");
37
+ var proccessToFunc = function (value, defaultV) {
38
+ var func;
39
+ if (!value) {
40
+ func = function (d) {
41
+ return defaultV || 1;
42
+ };
43
+ }
44
+ else if ((0, util_1.isNumber)(value)) {
45
+ func = function (d) {
46
+ return value;
47
+ };
48
+ }
49
+ else {
50
+ func = value;
51
+ }
52
+ return func;
53
+ };
54
+ /**
55
+ * graphin 中的 force 布局
56
+ */
57
+ var Force2Layout = /** @class */ (function (_super) {
58
+ __extends(Force2Layout, _super);
59
+ function Force2Layout(options) {
60
+ var _this = _super.call(this) || this;
61
+ /** 停止迭代的最大迭代数 */
62
+ _this.maxIteration = 500;
63
+ /** 停止迭代的最大迭代数,兼容 graphin-force */
64
+ _this.maxIterations = 500;
65
+ /** 是否启动 worker */
66
+ _this.workerEnabled = false;
67
+ /** 弹簧引力系数 */
68
+ _this.edgeStrength = 200;
69
+ /** 斥力系数 */
70
+ _this.nodeStrength = 1000;
71
+ /** 库伦系数 */
72
+ _this.coulombDisScale = 0.005;
73
+ /** 阻尼系数 */
74
+ _this.damping = 0.9;
75
+ /** 最大速度 */
76
+ _this.maxSpeed = 1000;
77
+ /** 一次迭代的平均移动距离小于该值时停止迭代 */
78
+ _this.minMovement = 0.4;
79
+ /** 迭代中衰减 */
80
+ _this.interval = 0.02;
81
+ /** 斥力的一个系数 */
82
+ _this.factor = 1;
83
+ /** 理想边长 */
84
+ _this.linkDistance = 200;
85
+ /** 重力大小 */
86
+ _this.gravity = 10;
87
+ /** 节点聚类作用力系数 */
88
+ _this.clusterNodeStrength = 20;
89
+ /** 是否防止重叠 */
90
+ _this.preventOverlap = true;
91
+ /** 防止重叠的力大小参数 */
92
+ _this.collideStrength = 1;
93
+ /** 阈值的使用条件,mean 代表平均移动距离小于 minMovement 时停止迭代,max 代表最大移动距离大时 minMovement 时停时迭代。默认为 mean */
94
+ _this.distanceThresholdMode = 'mean';
95
+ /** 每次迭代结束的回调函数 */
96
+ _this.tick = function () { };
97
+ _this.nodes = [];
98
+ _this.edges = [];
99
+ _this.width = 300;
100
+ _this.height = 300;
101
+ _this.nodeMap = {};
102
+ _this.nodeIdxMap = {};
103
+ _this.judgingDistance = 0;
104
+ /** 默认的向心配置 */
105
+ _this.centripetalOptions = {
106
+ leaf: 2,
107
+ single: 2,
108
+ others: 1,
109
+ // eslint-disable-next-line
110
+ center: function (n) {
111
+ return {
112
+ x: _this.width / 2,
113
+ y: _this.height / 2,
114
+ };
115
+ },
116
+ };
117
+ _this.updateCfg(options);
118
+ return _this;
119
+ }
120
+ Force2Layout.prototype.getCentripetalOptions = function () {
121
+ var _a = this, leafCluster = _a.leafCluster, clustering = _a.clustering, nodeClusterBy = _a.nodeClusterBy, nodes = _a.nodes, nodeMap = _a.nodeMap, propsClusterNodeStrength = _a.clusterNodeStrength;
122
+ var getClusterNodeStrength = function (node) {
123
+ return typeof propsClusterNodeStrength === 'function' ? propsClusterNodeStrength(node) : propsClusterNodeStrength;
124
+ };
125
+ var centripetalOptions = {};
126
+ var sameTypeLeafMap;
127
+ // 如果传入了需要叶子节点聚类
128
+ if (leafCluster) {
129
+ sameTypeLeafMap = this.getSameTypeLeafMap() || {};
130
+ var relativeNodesType_1 = Array.from(new Set(nodes === null || nodes === void 0 ? void 0 : nodes.map(function (node) { return node[nodeClusterBy]; }))) || [];
131
+ centripetalOptions = {
132
+ single: 100,
133
+ leaf: function (node, nodes, edges) {
134
+ // 找出与它关联的边的起点或终点出发的所有一度节点中同类型的叶子节点
135
+ var _a = sameTypeLeafMap[node.id] || {}, relativeLeafNodes = _a.relativeLeafNodes, sameTypeLeafNodes = _a.sameTypeLeafNodes;
136
+ // 如果都是同一类型或者每种类型只有1个,则施加默认向心力
137
+ if ((sameTypeLeafNodes === null || sameTypeLeafNodes === void 0 ? void 0 : sameTypeLeafNodes.length) === (relativeLeafNodes === null || relativeLeafNodes === void 0 ? void 0 : relativeLeafNodes.length) || (relativeNodesType_1 === null || relativeNodesType_1 === void 0 ? void 0 : relativeNodesType_1.length) === 1) {
138
+ return 1;
139
+ }
140
+ return getClusterNodeStrength(node);
141
+ },
142
+ others: 1,
143
+ center: function (node, nodes, edges) {
144
+ var _a;
145
+ var degree = (((_a = node.data) === null || _a === void 0 ? void 0 : _a.layout) || {}).degree;
146
+ // 孤点默认给1个远离的中心点
147
+ if (!degree) {
148
+ return {
149
+ x: 100,
150
+ y: 100,
151
+ };
152
+ }
153
+ var centerNode;
154
+ if (degree === 1) {
155
+ // 如果为叶子节点
156
+ // 找出与它关联的边的起点出发的所有一度节点中同类型的叶子节点
157
+ var _b = (sameTypeLeafMap[node.id] || {}).sameTypeLeafNodes, sameTypeLeafNodes = _b === void 0 ? [] : _b;
158
+ if (sameTypeLeafNodes.length === 1) {
159
+ // 如果同类型的叶子节点只有1个,中心节点置为undefined
160
+ centerNode = undefined;
161
+ }
162
+ else if (sameTypeLeafNodes.length > 1) {
163
+ // 找出同类型节点平均位置节点的距离最近的节点作为中心节点
164
+ centerNode = (0, util_1.getAvgNodePosition)(sameTypeLeafNodes);
165
+ }
166
+ }
167
+ else {
168
+ centerNode = undefined;
169
+ }
170
+ return {
171
+ x: centerNode === null || centerNode === void 0 ? void 0 : centerNode.x,
172
+ y: centerNode === null || centerNode === void 0 ? void 0 : centerNode.y,
173
+ };
174
+ },
175
+ };
176
+ }
177
+ // 如果传入了全局节点聚类
178
+ if (clustering) {
179
+ if (!sameTypeLeafMap)
180
+ sameTypeLeafMap = this.getSameTypeLeafMap();
181
+ var clusters = Array.from(new Set(nodes.map(function (node, i) {
182
+ return node[nodeClusterBy];
183
+ }))).filter(function (item) { return item !== undefined; });
184
+ var centerNodeInfo_1 = {};
185
+ clusters.forEach(function (cluster) {
186
+ var sameTypeNodes = nodes.filter(function (item) { return item[nodeClusterBy] === cluster; }).map(function (node) { return nodeMap[node.id]; });
187
+ // 找出同类型节点平均位置节点的距离最近的节点作为中心节点
188
+ centerNodeInfo_1[cluster] = (0, util_1.getAvgNodePosition)(sameTypeNodes);
189
+ });
190
+ centripetalOptions = {
191
+ single: function (node) { return getClusterNodeStrength(node); },
192
+ leaf: function (node) { return getClusterNodeStrength(node); },
193
+ others: function (node) { return getClusterNodeStrength(node); },
194
+ center: function (node, nodes, edges) {
195
+ // 找出同类型节点平均位置节点的距离最近的节点作为中心节点
196
+ var centerNode = centerNodeInfo_1[node[nodeClusterBy]];
197
+ return {
198
+ x: centerNode === null || centerNode === void 0 ? void 0 : centerNode.x,
199
+ y: centerNode === null || centerNode === void 0 ? void 0 : centerNode.y,
200
+ };
201
+ },
202
+ };
203
+ }
204
+ this.centripetalOptions = __assign(__assign({}, this.centripetalOptions), centripetalOptions);
205
+ var _b = this.centripetalOptions, leaf = _b.leaf, single = _b.single, others = _b.others;
206
+ if (leaf && typeof leaf !== 'function')
207
+ this.centripetalOptions.leaf = function () { return leaf; };
208
+ if (single && typeof single !== 'function')
209
+ this.centripetalOptions.single = function () { return single; };
210
+ if (others && typeof others !== 'function')
211
+ this.centripetalOptions.others = function () { return others; };
212
+ };
213
+ Force2Layout.prototype.updateCfg = function (cfg) {
214
+ if (cfg)
215
+ Object.assign(this, cfg);
216
+ };
217
+ Force2Layout.prototype.getDefaultCfg = function () {
218
+ return {
219
+ maxIteration: 500,
220
+ gravity: 10,
221
+ enableTick: true,
222
+ animate: true,
223
+ };
224
+ };
225
+ /**
226
+ * 执行布局
227
+ */
228
+ Force2Layout.prototype.execute = function () {
229
+ var self = this;
230
+ self.stop();
231
+ var nodes = self.nodes, edges = self.edges, defSpringLen = self.defSpringLen;
232
+ self.judgingDistance = 0;
233
+ if (!nodes || nodes.length === 0) {
234
+ self.onLayoutEnd([]);
235
+ return;
236
+ }
237
+ if (!self.width && typeof window !== "undefined") {
238
+ self.width = window.innerWidth;
239
+ }
240
+ if (!self.height && typeof window !== "undefined") {
241
+ self.height = window.innerHeight;
242
+ }
243
+ if (!self.center) {
244
+ self.center = [self.width / 2, self.height / 2];
245
+ }
246
+ var center = self.center;
247
+ if (nodes.length === 1) {
248
+ nodes[0].x = center[0];
249
+ nodes[0].y = center[1];
250
+ self.onLayoutEnd([__assign({}, node[0])]);
251
+ return;
252
+ }
253
+ self.degreesMap = (0, util_1.getDegreeMap)(nodes, edges);
254
+ if (!self.getMass) {
255
+ self.getMass = function (d) {
256
+ var massWeight = 1;
257
+ if ((0, util_1.isNumber)(d.mass))
258
+ massWeight = d.mass;
259
+ var degree = self.degreesMap[d.id].all;
260
+ return (!degree || degree < 5) ? massWeight : degree * 5 * massWeight;
261
+ };
262
+ }
263
+ // node size function
264
+ var nodeSize = self.nodeSize;
265
+ var nodeSizeFunc;
266
+ if (self.preventOverlap) {
267
+ var nodeSpacing_1 = self.nodeSpacing;
268
+ var nodeSpacingFunc_1;
269
+ if ((0, util_1.isNumber)(nodeSpacing_1)) {
270
+ nodeSpacingFunc_1 = function () { return nodeSpacing_1; };
271
+ }
272
+ else if ((0, util_1.isFunction)(nodeSpacing_1)) {
273
+ nodeSpacingFunc_1 = nodeSpacing_1;
274
+ }
275
+ else {
276
+ nodeSpacingFunc_1 = function () { return 0; };
277
+ }
278
+ if (!nodeSize) {
279
+ nodeSizeFunc = function (d) {
280
+ if (d.size) {
281
+ if ((0, util_1.isArray)(d.size)) {
282
+ return Math.max(d.size[0], d.size[1]) + nodeSpacingFunc_1(d);
283
+ }
284
+ if ((0, util_1.isObject)(d.size)) {
285
+ return Math.max(d.size.width, d.size.height) + nodeSpacingFunc_1(d);
286
+ }
287
+ return d.size + nodeSpacingFunc_1(d);
288
+ }
289
+ return 10 + nodeSpacingFunc_1(d);
290
+ };
291
+ }
292
+ else if ((0, util_1.isArray)(nodeSize)) {
293
+ nodeSizeFunc = function (d) {
294
+ return Math.max(nodeSize[0], nodeSize[1]) + nodeSpacingFunc_1(d);
295
+ };
296
+ }
297
+ else {
298
+ nodeSizeFunc = function (d) { return nodeSize + nodeSpacingFunc_1(d); };
299
+ }
300
+ }
301
+ self.nodeSize = nodeSizeFunc;
302
+ self.linkDistance = proccessToFunc(self.linkDistance, 1);
303
+ self.nodeStrength = proccessToFunc(self.nodeStrength, 1);
304
+ self.edgeStrength = proccessToFunc(self.edgeStrength, 1);
305
+ var nodeMap = {};
306
+ var nodeIdxMap = {};
307
+ nodes.forEach(function (node, i) {
308
+ if (!(0, util_1.isNumber)(node.x))
309
+ node.x = Math.random() * self.width;
310
+ if (!(0, util_1.isNumber)(node.y))
311
+ node.y = Math.random() * self.height;
312
+ var degree = self.degreesMap[node.id];
313
+ nodeMap[node.id] = __assign(__assign({}, node), { data: __assign(__assign({}, node.data), { size: self.nodeSize(node) || 30, layout: {
314
+ inDegree: degree.in,
315
+ outDegree: degree.out,
316
+ degree: degree.all,
317
+ tDegree: degree.in,
318
+ sDegree: degree.out,
319
+ force: {
320
+ mass: self.getMass(node),
321
+ nodeStrength: self.nodeStrength(node)
322
+ }
323
+ } }) });
324
+ nodeIdxMap[node.id] = i;
325
+ });
326
+ self.nodeMap = nodeMap;
327
+ self.nodeIdxMap = nodeIdxMap;
328
+ self.edgeInfos = [];
329
+ edges === null || edges === void 0 ? void 0 : edges.forEach(function (edge) {
330
+ var sourceNode = nodeMap[edge.source];
331
+ var targetNode = nodeMap[edge.target];
332
+ if (!sourceNode || !targetNode) {
333
+ elf.edgeInfos.push({});
334
+ }
335
+ else {
336
+ self.edgeInfos.push({
337
+ edgeStrength: self.edgeStrength(edge),
338
+ linkDistance: defSpringLen ? defSpringLen(__assign(__assign({}, edge), { source: sourceNode, target: targetNode }), sourceNode, targetNode) : self.linkDistance(edge, sourceNode, targetNode) || 1 + ((nodeSize(sourceNode) + nodeSize(sourceNode)) || 0) / 2
339
+ });
340
+ }
341
+ });
342
+ this.getCentripetalOptions();
343
+ self.onLayoutEnd = self.onLayoutEnd || (function () { });
344
+ self.run();
345
+ };
346
+ Force2Layout.prototype.run = function () {
347
+ var self = this;
348
+ var maxIteration = self.maxIteration, maxIterations = self.maxIterations, nodes = self.nodes, workerEnabled = self.workerEnabled, minMovement = self.minMovement, animate = self.animate, minMovement = self.minMovement, nodeMap = self.nodeMap;
349
+ if (!nodes)
350
+ return;
351
+ var velArray = [];
352
+ nodes.forEach(function (_, i) {
353
+ velArray[2 * i] = 0;
354
+ velArray[2 * i + 1] = 0;
355
+ });
356
+ var maxIter = maxIterations || maxIteration;
357
+ var silence = !animate;
358
+ if (workerEnabled || silence) {
359
+ var usedIter = 0;
360
+ for (var i = 0; (self.judgingDistance > minMovement || i < 1) && i < maxIter; i++) {
361
+ usedIter = i;
362
+ self.runOneStep(i, velArray);
363
+ }
364
+ self.onLayoutEnd(Object.values(nodeMap));
365
+ }
366
+ else {
367
+ if (typeof window === "undefined")
368
+ return;
369
+ var iter_1 = 0;
370
+ // interval for render the result after each iteration
371
+ this.timeInterval = window.setInterval(function () {
372
+ if (!nodes)
373
+ return;
374
+ self.runOneStep(iter_1, velArray);
375
+ iter_1++;
376
+ if (iter_1 >= maxIter || self.judgingDistance < minMovement) {
377
+ self.onLayoutEnd(Object.values(nodeMap));
378
+ window.clearInterval(self.timeInterval);
379
+ }
380
+ }, 0);
381
+ }
382
+ };
383
+ Force2Layout.prototype.runOneStep = function (iter, velArray) {
384
+ var _a;
385
+ var self = this;
386
+ var nodes = self.nodes, edges = self.edges, nodeMap = self.nodeMap, monitor = self.monitor;
387
+ var accArray = [];
388
+ if (!(nodes === null || nodes === void 0 ? void 0 : nodes.length))
389
+ return;
390
+ self.calRepulsive(accArray);
391
+ if (edges)
392
+ self.calAttractive(accArray);
393
+ self.calGravity(accArray);
394
+ var stepInterval = self.interval; // Math.max(0.02, self.interval - iter * 0.002);
395
+ self.updateVelocity(accArray, velArray, stepInterval);
396
+ self.updatePosition(velArray, stepInterval);
397
+ (_a = self.tick) === null || _a === void 0 ? void 0 : _a.call(self);
398
+ /** 如果需要监控信息,则提供给用户 */
399
+ if (monitor) {
400
+ var energy = this.calTotalEnergy(accArray);
401
+ monitor({ energy: energy, nodes: nodes, edges: edges, iterations: iter });
402
+ }
403
+ };
404
+ Force2Layout.prototype.calTotalEnergy = function (accArray) {
405
+ var _a = this, nodes = _a.nodes, nodeMap = _a.nodeMap;
406
+ if (!(nodes === null || nodes === void 0 ? void 0 : nodes.length))
407
+ return 0;
408
+ var energy = 0.0;
409
+ nodes.forEach(function (node, i) {
410
+ var vx = accArray[2 * i];
411
+ var vy = accArray[2 * i + 1];
412
+ var speed2 = vx * vx + vy * vy;
413
+ var _a = nodeMap[node.id].data.layout.force.mass, mass = _a === void 0 ? 1 : _a;
414
+ energy += mass * speed2 * 0.5; // p = 1/2*(mv^2)
415
+ });
416
+ return energy;
417
+ };
418
+ ;
419
+ // coulombs law
420
+ Force2Layout.prototype.calRepulsive = function (accArray) {
421
+ var self = this;
422
+ var nodes = self.nodes, nodeMap = self.nodeMap, factor = self.factor, coulombDisScale = self.coulombDisScale;
423
+ var nodeSize = self.nodeSize;
424
+ (0, ForceNBody_1.forceNBody)(nodes, nodeMap, factor, coulombDisScale * coulombDisScale, accArray);
425
+ };
426
+ // hooks law
427
+ Force2Layout.prototype.calAttractive = function (accArray) {
428
+ var self = this;
429
+ var edges = self.edges, nodeMap = self.nodeMap, nodeIdxMap = self.nodeIdxMap, edgeInfos = self.edgeInfos;
430
+ var nodeSize = self.nodeSize;
431
+ edges.forEach(function (edge, i) {
432
+ var source = (0, util_1.getEdgeTerminal)(edge, 'source');
433
+ var target = (0, util_1.getEdgeTerminal)(edge, 'target');
434
+ var sourceNode = nodeMap[source];
435
+ var targetNode = nodeMap[target];
436
+ if (!sourceNode || !targetNode)
437
+ return;
438
+ var vecX = targetNode.x - sourceNode.x;
439
+ var vecY = targetNode.y - sourceNode.y;
440
+ if (!vecX && !vecY) {
441
+ vecX = Math.random() * 0.01;
442
+ vecY = Math.random() * 0.01;
443
+ }
444
+ var vecLength = Math.sqrt(vecX * vecX + vecY * vecY);
445
+ var direX = vecX / vecLength;
446
+ var direY = vecY / vecLength;
447
+ // @ts-ignore
448
+ var _a = edgeInfos[i] || {}, _b = _a.linkDistance, linkDistance = _b === void 0 ? 200 : _b, _c = _a.edgeStrength, edgeStrength = _c === void 0 ? 200 : _c;
449
+ var diff = linkDistance - vecLength;
450
+ var param = diff * edgeStrength;
451
+ var massSource = sourceNode.data.layout.force.mass || 1;
452
+ var massTarget = targetNode.data.layout.force.mass || 1;
453
+ // 质量占比越大,对另一端影响程度越大
454
+ var sourceMassRatio = 1 / massSource;
455
+ var targetMassRatio = 1 / massTarget;
456
+ var disX = direX * param;
457
+ var disY = direY * param;
458
+ var sourceIdx = 2 * nodeIdxMap[source];
459
+ var targetIdx = 2 * nodeIdxMap[target];
460
+ accArray[sourceIdx] -= disX * sourceMassRatio;
461
+ accArray[sourceIdx + 1] -= disY * sourceMassRatio;
462
+ accArray[targetIdx] += disX * targetMassRatio;
463
+ accArray[targetIdx + 1] += disY * targetMassRatio;
464
+ });
465
+ };
466
+ // attract to center
467
+ Force2Layout.prototype.calGravity = function (accArray) {
468
+ var _a;
469
+ var self = this;
470
+ var nodes = self.nodes, _b = self.edges, edges = _b === void 0 ? [] : _b, nodeMap = self.nodeMap, width = self.width, height = self.height, center = self.center, defaultGravity = self.gravity, degreesMap = self.degreesMap, centripetalOptions = self.centripetalOptions;
471
+ if (!nodes)
472
+ return;
473
+ var nodeLength = nodes.length;
474
+ for (var i = 0; i < nodeLength; i++) {
475
+ var idx = 2 * i;
476
+ var node = nodeMap[nodes[i].id];
477
+ var _c = node.data.layout.force.mass, mass = _c === void 0 ? 1 : _c;
478
+ var vecX = 0;
479
+ var vecY = 0;
480
+ var gravity = defaultGravity;
481
+ var _d = degreesMap[node.id], inDegree = _d.in, outDegree = _d.out, degree = _d.all;
482
+ var forceCenter = (_a = self.getCenter) === null || _a === void 0 ? void 0 : _a.call(self, node, degree);
483
+ if (forceCenter) {
484
+ var centerX = forceCenter[0], centerY = forceCenter[1], strength = forceCenter[2];
485
+ vecX = node.x - centerX;
486
+ vecY = node.y - centerY;
487
+ gravity = strength;
488
+ }
489
+ else {
490
+ vecX = node.x - center[0];
491
+ vecY = node.y - center[1];
492
+ }
493
+ if (gravity) {
494
+ accArray[idx] -= gravity * vecX / mass;
495
+ accArray[idx + 1] -= gravity * vecY / mass;
496
+ }
497
+ if (centripetalOptions) {
498
+ var leaf = centripetalOptions.leaf, single = centripetalOptions.single, others = centripetalOptions.others, centriCenter = centripetalOptions.center;
499
+ var _e = (centriCenter === null || centriCenter === void 0 ? void 0 : centriCenter(node, nodes, edges, width, height)) || { x: 0, y: 0, centerStrength: 0 }, centriX = _e.x, centriY = _e.y, centerStrength = _e.centerStrength;
500
+ if (!(0, util_1.isNumber)(centriX) || !(0, util_1.isNumber)(centriY))
501
+ continue;
502
+ var vx = (node.x - centriX) / mass;
503
+ var vy = (node.y - centriY) / mass;
504
+ if (centerStrength) {
505
+ accArray[idx] -= centerStrength * vx;
506
+ accArray[idx + 1] -= centerStrength * vy;
507
+ }
508
+ // 孤点
509
+ if (degree === 0) {
510
+ var singleStrength = single(node);
511
+ if (!singleStrength)
512
+ continue;
513
+ accArray[idx] -= singleStrength * vx;
514
+ accArray[idx + 1] -= singleStrength * vy;
515
+ continue;
516
+ }
517
+ // 没有出度或没有入度,都认为是叶子节点
518
+ if (inDegree === 0 || outDegree === 0) {
519
+ var leafStrength = leaf(node, nodes, edges);
520
+ if (!leafStrength)
521
+ continue;
522
+ accArray[idx] -= leafStrength * vx;
523
+ accArray[idx + 1] -= leafStrength * vy;
524
+ continue;
525
+ }
526
+ /** others */
527
+ var othersStrength = others(node);
528
+ if (!othersStrength)
529
+ continue;
530
+ accArray[idx] -= othersStrength * vx;
531
+ accArray[idx + 1] -= othersStrength * vy;
532
+ }
533
+ }
534
+ };
535
+ // TODO: 待 graphin 修改正确
536
+ // public attractToSide(accArray: number[]) {
537
+ // const { defSideCoe, height, nodes } = this;
538
+ // if (!defSideCoe || typeof defSideCoe !== 'function' || !nodes?.length) return;
539
+ // nodes.forEach((node, i) => {
540
+ // const sideCoe = defSideCoe!(node);
541
+ // if (sideCoe === 0) return;
542
+ // const targetY = sideCoe > 0 ? 0 : height;
543
+ // const strength = Math.abs(sideCoe);
544
+ // accArray[2 * i + 1] -= strength * (targetY - node.y);
545
+ // });
546
+ // };
547
+ Force2Layout.prototype.updateVelocity = function (accArray, velArray, stepInterval) {
548
+ var self = this;
549
+ var nodes = self.nodes, damping = self.damping, maxSpeed = self.maxSpeed;
550
+ if (!(nodes === null || nodes === void 0 ? void 0 : nodes.length))
551
+ return;
552
+ nodes.forEach(function (_, i) {
553
+ var vx = (velArray[2 * i] + accArray[2 * i] * stepInterval) * damping || 0.01;
554
+ var vy = (velArray[2 * i + 1] + accArray[2 * i + 1] * stepInterval) * damping || 0.01;
555
+ var vLength = Math.sqrt(vx * vx + vy * vy);
556
+ if (vLength > maxSpeed) {
557
+ var param2 = maxSpeed / vLength;
558
+ vx = param2 * vx;
559
+ vy = param2 * vy;
560
+ }
561
+ velArray[2 * i] = vx;
562
+ velArray[2 * i + 1] = vy;
563
+ });
564
+ };
565
+ Force2Layout.prototype.updatePosition = function (velArray, stepInterval) {
566
+ var self = this;
567
+ var nodes = self.nodes, distanceThresholdMode = self.distanceThresholdMode, nodeMap = self.nodeMap;
568
+ if (!(nodes === null || nodes === void 0 ? void 0 : nodes.length)) {
569
+ this.judgingDistance = 0;
570
+ return;
571
+ }
572
+ var sum = 0;
573
+ if (distanceThresholdMode === 'max')
574
+ self.judgingDistance = -Infinity;
575
+ else if (distanceThresholdMode === 'min')
576
+ self.judgingDistance = Infinity;
577
+ nodes.forEach(function (node, i) {
578
+ var mappedNode = nodeMap[node.id];
579
+ if ((0, util_1.isNumber)(node.fx) && (0, util_1.isNumber)(node.fy)) {
580
+ node.x = node.fx;
581
+ node.y = node.fy;
582
+ mappedNode.x = node.x;
583
+ mappedNode.y = node.y;
584
+ return;
585
+ }
586
+ var distX = velArray[2 * i] * stepInterval;
587
+ var distY = velArray[2 * i + 1] * stepInterval;
588
+ node.x += distX;
589
+ node.y += distY;
590
+ mappedNode.x = node.x;
591
+ mappedNode.y = node.y;
592
+ var distanceMagnitude = Math.sqrt(distX * distX + distY * distY);
593
+ switch (distanceThresholdMode) {
594
+ case 'max':
595
+ if (self.judgingDistance < distanceMagnitude)
596
+ self.judgingDistance = distanceMagnitude;
597
+ break;
598
+ case 'min':
599
+ if (self.judgingDistance > distanceMagnitude)
600
+ self.judgingDistance = distanceMagnitude;
601
+ break;
602
+ default:
603
+ sum = sum + distanceMagnitude;
604
+ break;
605
+ }
606
+ });
607
+ if (!distanceThresholdMode || distanceThresholdMode === 'mean')
608
+ self.judgingDistance = sum / nodes.length;
609
+ };
610
+ Force2Layout.prototype.stop = function () {
611
+ if (this.timeInterval && typeof window !== "undefined") {
612
+ window.clearInterval(this.timeInterval);
613
+ }
614
+ };
615
+ Force2Layout.prototype.destroy = function () {
616
+ var self = this;
617
+ self.stop();
618
+ self.tick = null;
619
+ self.nodes = null;
620
+ self.edges = null;
621
+ self.destroyed = true;
622
+ };
623
+ Force2Layout.prototype.getType = function () {
624
+ return "force2";
625
+ };
626
+ Force2Layout.prototype.getSameTypeLeafMap = function () {
627
+ var _a = this, nodeClusterBy = _a.nodeClusterBy, nodes = _a.nodes, edges = _a.edges, nodeMap = _a.nodeMap, degreesMap = _a.degreesMap;
628
+ if (!(nodes === null || nodes === void 0 ? void 0 : nodes.length))
629
+ return;
630
+ // eslint-disable-next-line
631
+ var sameTypeLeafMap = {};
632
+ nodes.forEach(function (node, i) {
633
+ var degree = degreesMap[node.id].all;
634
+ if (degree === 1) {
635
+ sameTypeLeafMap[node.id] = (0, util_1.getCoreNodeAndRelativeLeafNodes)('leaf', node, edges, nodeClusterBy, degreesMap, nodeMap);
636
+ }
637
+ });
638
+ return sameTypeLeafMap;
639
+ };
640
+ ;
641
+ return Force2Layout;
642
+ }(base_1.Base));
643
+ exports.Force2Layout = Force2Layout;
644
+ //# sourceMappingURL=index.js.map