@vunk/graph 0.0.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.
Files changed (83) hide show
  1. package/api/index.d.ts +0 -0
  2. package/api/index.mjs +1 -0
  3. package/api/user/index.d.ts +3 -0
  4. package/api/user/index.mjs +18 -0
  5. package/api/user/types.d.ts +5 -0
  6. package/components/_plugin-vue_export-helper.mjs +9 -0
  7. package/components/context-menu/index.css +1 -0
  8. package/components/context-menu/index.d.ts +2 -0
  9. package/components/context-menu/index.mjs +1797 -0
  10. package/components/graph/index.css +5 -0
  11. package/components/graph/index.d.ts +6 -0
  12. package/components/graph/index.mjs +110 -0
  13. package/components/graph/src/ctx.d.ts +12 -0
  14. package/components/graph/src/index.vue.d.ts +74 -0
  15. package/components/graph/src/types.d.ts +7 -0
  16. package/components/graph/src/useGraph.d.ts +3 -0
  17. package/components/graph/src/useSigma.d.ts +3 -0
  18. package/components/graph-view-ui/index.css +8 -0
  19. package/components/graph-view-ui/index.d.ts +4 -0
  20. package/components/graph-view-ui/index.mjs +81 -0
  21. package/components/graph-view-ui/src/ctx.d.ts +11 -0
  22. package/components/graph-view-ui/src/index.vue.d.ts +17 -0
  23. package/components/graph-view-ui/src/types.d.ts +1 -0
  24. package/components/hover-edge/index.d.ts +4 -0
  25. package/components/hover-edge/index.mjs +179 -0
  26. package/components/hover-edge/src/ctx.d.ts +42 -0
  27. package/components/hover-edge/src/index.vue.d.ts +194 -0
  28. package/components/hover-edge/src/types.d.ts +4 -0
  29. package/components/hover-highlight/index.d.ts +4 -0
  30. package/components/hover-highlight/index.mjs +133 -0
  31. package/components/hover-highlight/src/ctx.d.ts +33 -0
  32. package/components/hover-highlight/src/index.vue.d.ts +45 -0
  33. package/components/hover-highlight/src/types.d.ts +1 -0
  34. package/components/hover-node/index.d.ts +4 -0
  35. package/components/hover-node/index.mjs +146 -0
  36. package/components/hover-node/src/ctx.d.ts +35 -0
  37. package/components/hover-node/src/index.vue.d.ts +148 -0
  38. package/components/hover-node/src/types.d.ts +4 -0
  39. package/components/label/index.css +30 -0
  40. package/components/label/index.d.ts +6 -0
  41. package/components/label/index.mjs +145 -0
  42. package/components/label/src/core.d.ts +5 -0
  43. package/components/label/src/ctx.d.ts +24 -0
  44. package/components/label/src/index.vue.d.ts +33 -0
  45. package/components/label/src/types.d.ts +1 -0
  46. package/components/label/src/view.vue.d.ts +28 -0
  47. package/components/layout-forceatlas2/index.d.ts +5 -0
  48. package/components/layout-forceatlas2/index.mjs +1617 -0
  49. package/components/layout-forceatlas2/src/ctx.d.ts +9 -0
  50. package/components/layout-forceatlas2/src/index.vue.d.ts +14 -0
  51. package/components/layout-forceatlas2/src/types.d.ts +1 -0
  52. package/components/layout-forceatlas2/src/use.d.ts +16 -0
  53. package/components/link-guide/index.css +9 -0
  54. package/components/link-guide/index.d.ts +4 -0
  55. package/components/link-guide/index.mjs +118 -0
  56. package/components/link-guide/src/ctx.d.ts +11 -0
  57. package/components/link-guide/src/index.vue.d.ts +27 -0
  58. package/components/link-guide/src/types.d.ts +1 -0
  59. package/components/popup/index.css +32 -0
  60. package/components/popup/index.d.ts +5 -0
  61. package/components/popup/index.mjs +136 -0
  62. package/components/popup/src/core.d.ts +24 -0
  63. package/components/popup/src/ctx.d.ts +16 -0
  64. package/components/popup/src/index.vue.d.ts +73 -0
  65. package/components/popup/src/provider.vue.d.ts +46 -0
  66. package/components/popup/src/types.d.ts +1 -0
  67. package/components/search/index.d.ts +4 -0
  68. package/components/search/index.mjs +218 -0
  69. package/components/search/src/ctx.d.ts +53 -0
  70. package/components/search/src/index.vue.d.ts +83 -0
  71. package/components/search/src/types.d.ts +16 -0
  72. package/composables/index.d.ts +1 -0
  73. package/composables/index.mjs +1 -0
  74. package/index.css +90 -0
  75. package/index.d.ts +10 -0
  76. package/index.esm.js +10 -0
  77. package/package.json +108 -0
  78. package/shared/graph/index.d.ts +17 -0
  79. package/shared/graph/index.mjs +19 -0
  80. package/shared/index.d.ts +0 -0
  81. package/shared/index.mjs +1 -0
  82. package/stores/index.d.ts +0 -0
  83. package/stores/index.mjs +1 -0
@@ -0,0 +1,1617 @@
1
+ import { shallowRef, onBeforeUnmount, provide, inject, defineComponent, renderSlot } from 'vue';
2
+ import { useGraph } from '@vunk/graph/composables';
3
+ import forceAtlas2 from 'graphology-layout-forceatlas2';
4
+ import { _ as _export_sfc } from '../_plugin-vue_export-helper.mjs';
5
+
6
+ const props = {
7
+ settings: {
8
+ type: Object,
9
+ default: () => ({})
10
+ }
11
+ };
12
+
13
+ function getDefaultExportFromCjs (x) {
14
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
15
+ }
16
+
17
+ /**
18
+ * Graphology ForceAtlas2 Layout Webworker
19
+ * ========================================
20
+ *
21
+ * Web worker able to run the layout in a separate thread.
22
+ */
23
+
24
+ var webworker;
25
+ var hasRequiredWebworker;
26
+
27
+ function requireWebworker () {
28
+ if (hasRequiredWebworker) return webworker;
29
+ hasRequiredWebworker = 1;
30
+ webworker = function worker() {
31
+ var NODES, EDGES;
32
+
33
+ var moduleShim = {};
34
+
35
+ (function () {
36
+ /* eslint no-constant-condition: 0 */
37
+ /**
38
+ * Graphology ForceAtlas2 Iteration
39
+ * =================================
40
+ *
41
+ * Function used to perform a single iteration of the algorithm.
42
+ */
43
+
44
+ /**
45
+ * Matrices properties accessors.
46
+ */
47
+ var NODE_X = 0;
48
+ var NODE_Y = 1;
49
+ var NODE_DX = 2;
50
+ var NODE_DY = 3;
51
+ var NODE_OLD_DX = 4;
52
+ var NODE_OLD_DY = 5;
53
+ var NODE_MASS = 6;
54
+ var NODE_CONVERGENCE = 7;
55
+ var NODE_SIZE = 8;
56
+ var NODE_FIXED = 9;
57
+
58
+ var EDGE_SOURCE = 0;
59
+ var EDGE_TARGET = 1;
60
+ var EDGE_WEIGHT = 2;
61
+
62
+ var REGION_NODE = 0;
63
+ var REGION_CENTER_X = 1;
64
+ var REGION_CENTER_Y = 2;
65
+ var REGION_SIZE = 3;
66
+ var REGION_NEXT_SIBLING = 4;
67
+ var REGION_FIRST_CHILD = 5;
68
+ var REGION_MASS = 6;
69
+ var REGION_MASS_CENTER_X = 7;
70
+ var REGION_MASS_CENTER_Y = 8;
71
+
72
+ var SUBDIVISION_ATTEMPTS = 3;
73
+
74
+ /**
75
+ * Constants.
76
+ */
77
+ var PPN = 10;
78
+ var PPE = 3;
79
+ var PPR = 9;
80
+
81
+ var MAX_FORCE = 10;
82
+
83
+ /**
84
+ * Function used to perform a single interation of the algorithm.
85
+ *
86
+ * @param {object} options - Layout options.
87
+ * @param {Float32Array} NodeMatrix - Node data.
88
+ * @param {Float32Array} EdgeMatrix - Edge data.
89
+ * @return {object} - Some metadata.
90
+ */
91
+ moduleShim.exports = function iterate(options, NodeMatrix, EdgeMatrix) {
92
+ // Initializing variables
93
+ var l, r, n, n1, n2, rn, e, w, g, s;
94
+
95
+ var order = NodeMatrix.length,
96
+ size = EdgeMatrix.length;
97
+
98
+ var adjustSizes = options.adjustSizes;
99
+
100
+ var thetaSquared = options.barnesHutTheta * options.barnesHutTheta;
101
+
102
+ var outboundAttCompensation, coefficient, xDist, yDist, ewc, distance, factor;
103
+
104
+ var RegionMatrix = [];
105
+
106
+ // 1) Initializing layout data
107
+ //-----------------------------
108
+
109
+ // Resetting positions & computing max values
110
+ for (n = 0; n < order; n += PPN) {
111
+ NodeMatrix[n + NODE_OLD_DX] = NodeMatrix[n + NODE_DX];
112
+ NodeMatrix[n + NODE_OLD_DY] = NodeMatrix[n + NODE_DY];
113
+ NodeMatrix[n + NODE_DX] = 0;
114
+ NodeMatrix[n + NODE_DY] = 0;
115
+ }
116
+
117
+ // If outbound attraction distribution, compensate
118
+ if (options.outboundAttractionDistribution) {
119
+ outboundAttCompensation = 0;
120
+ for (n = 0; n < order; n += PPN) {
121
+ outboundAttCompensation += NodeMatrix[n + NODE_MASS];
122
+ }
123
+
124
+ outboundAttCompensation /= order / PPN;
125
+ }
126
+
127
+ // 1.bis) Barnes-Hut computation
128
+ //------------------------------
129
+
130
+ if (options.barnesHutOptimize) {
131
+ // Setting up
132
+ var minX = Infinity,
133
+ maxX = -Infinity,
134
+ minY = Infinity,
135
+ maxY = -Infinity,
136
+ q,
137
+ q2,
138
+ subdivisionAttempts;
139
+
140
+ // Computing min and max values
141
+ for (n = 0; n < order; n += PPN) {
142
+ minX = Math.min(minX, NodeMatrix[n + NODE_X]);
143
+ maxX = Math.max(maxX, NodeMatrix[n + NODE_X]);
144
+ minY = Math.min(minY, NodeMatrix[n + NODE_Y]);
145
+ maxY = Math.max(maxY, NodeMatrix[n + NODE_Y]);
146
+ }
147
+
148
+ // squarify bounds, it's a quadtree
149
+ var dx = maxX - minX,
150
+ dy = maxY - minY;
151
+ if (dx > dy) {
152
+ minY -= (dx - dy) / 2;
153
+ maxY = minY + dx;
154
+ } else {
155
+ minX -= (dy - dx) / 2;
156
+ maxX = minX + dy;
157
+ }
158
+
159
+ // Build the Barnes Hut root region
160
+ RegionMatrix[0 + REGION_NODE] = -1;
161
+ RegionMatrix[0 + REGION_CENTER_X] = (minX + maxX) / 2;
162
+ RegionMatrix[0 + REGION_CENTER_Y] = (minY + maxY) / 2;
163
+ RegionMatrix[0 + REGION_SIZE] = Math.max(maxX - minX, maxY - minY);
164
+ RegionMatrix[0 + REGION_NEXT_SIBLING] = -1;
165
+ RegionMatrix[0 + REGION_FIRST_CHILD] = -1;
166
+ RegionMatrix[0 + REGION_MASS] = 0;
167
+ RegionMatrix[0 + REGION_MASS_CENTER_X] = 0;
168
+ RegionMatrix[0 + REGION_MASS_CENTER_Y] = 0;
169
+
170
+ // Add each node in the tree
171
+ l = 1;
172
+ for (n = 0; n < order; n += PPN) {
173
+ // Current region, starting with root
174
+ r = 0;
175
+ subdivisionAttempts = SUBDIVISION_ATTEMPTS;
176
+
177
+ while (true) {
178
+ // Are there sub-regions?
179
+
180
+ // We look at first child index
181
+ if (RegionMatrix[r + REGION_FIRST_CHILD] >= 0) {
182
+ // There are sub-regions
183
+
184
+ // We just iterate to find a "leaf" of the tree
185
+ // that is an empty region or a region with a single node
186
+ // (see next case)
187
+
188
+ // Find the quadrant of n
189
+ if (NodeMatrix[n + NODE_X] < RegionMatrix[r + REGION_CENTER_X]) {
190
+ if (NodeMatrix[n + NODE_Y] < RegionMatrix[r + REGION_CENTER_Y]) {
191
+ // Top Left quarter
192
+ q = RegionMatrix[r + REGION_FIRST_CHILD];
193
+ } else {
194
+ // Bottom Left quarter
195
+ q = RegionMatrix[r + REGION_FIRST_CHILD] + PPR;
196
+ }
197
+ } else {
198
+ if (NodeMatrix[n + NODE_Y] < RegionMatrix[r + REGION_CENTER_Y]) {
199
+ // Top Right quarter
200
+ q = RegionMatrix[r + REGION_FIRST_CHILD] + PPR * 2;
201
+ } else {
202
+ // Bottom Right quarter
203
+ q = RegionMatrix[r + REGION_FIRST_CHILD] + PPR * 3;
204
+ }
205
+ }
206
+
207
+ // Update center of mass and mass (we only do it for non-leave regions)
208
+ RegionMatrix[r + REGION_MASS_CENTER_X] =
209
+ (RegionMatrix[r + REGION_MASS_CENTER_X] *
210
+ RegionMatrix[r + REGION_MASS] +
211
+ NodeMatrix[n + NODE_X] * NodeMatrix[n + NODE_MASS]) /
212
+ (RegionMatrix[r + REGION_MASS] + NodeMatrix[n + NODE_MASS]);
213
+
214
+ RegionMatrix[r + REGION_MASS_CENTER_Y] =
215
+ (RegionMatrix[r + REGION_MASS_CENTER_Y] *
216
+ RegionMatrix[r + REGION_MASS] +
217
+ NodeMatrix[n + NODE_Y] * NodeMatrix[n + NODE_MASS]) /
218
+ (RegionMatrix[r + REGION_MASS] + NodeMatrix[n + NODE_MASS]);
219
+
220
+ RegionMatrix[r + REGION_MASS] += NodeMatrix[n + NODE_MASS];
221
+
222
+ // Iterate on the right quadrant
223
+ r = q;
224
+ continue;
225
+ } else {
226
+ // There are no sub-regions: we are in a "leaf"
227
+
228
+ // Is there a node in this leave?
229
+ if (RegionMatrix[r + REGION_NODE] < 0) {
230
+ // There is no node in region:
231
+ // we record node n and go on
232
+ RegionMatrix[r + REGION_NODE] = n;
233
+ break;
234
+ } else {
235
+ // There is a node in this region
236
+
237
+ // We will need to create sub-regions, stick the two
238
+ // nodes (the old one r[0] and the new one n) in two
239
+ // subregions. If they fall in the same quadrant,
240
+ // we will iterate.
241
+
242
+ // Create sub-regions
243
+ RegionMatrix[r + REGION_FIRST_CHILD] = l * PPR;
244
+ w = RegionMatrix[r + REGION_SIZE] / 2; // new size (half)
245
+
246
+ // NOTE: we use screen coordinates
247
+ // from Top Left to Bottom Right
248
+
249
+ // Top Left sub-region
250
+ g = RegionMatrix[r + REGION_FIRST_CHILD];
251
+
252
+ RegionMatrix[g + REGION_NODE] = -1;
253
+ RegionMatrix[g + REGION_CENTER_X] =
254
+ RegionMatrix[r + REGION_CENTER_X] - w;
255
+ RegionMatrix[g + REGION_CENTER_Y] =
256
+ RegionMatrix[r + REGION_CENTER_Y] - w;
257
+ RegionMatrix[g + REGION_SIZE] = w;
258
+ RegionMatrix[g + REGION_NEXT_SIBLING] = g + PPR;
259
+ RegionMatrix[g + REGION_FIRST_CHILD] = -1;
260
+ RegionMatrix[g + REGION_MASS] = 0;
261
+ RegionMatrix[g + REGION_MASS_CENTER_X] = 0;
262
+ RegionMatrix[g + REGION_MASS_CENTER_Y] = 0;
263
+
264
+ // Bottom Left sub-region
265
+ g += PPR;
266
+ RegionMatrix[g + REGION_NODE] = -1;
267
+ RegionMatrix[g + REGION_CENTER_X] =
268
+ RegionMatrix[r + REGION_CENTER_X] - w;
269
+ RegionMatrix[g + REGION_CENTER_Y] =
270
+ RegionMatrix[r + REGION_CENTER_Y] + w;
271
+ RegionMatrix[g + REGION_SIZE] = w;
272
+ RegionMatrix[g + REGION_NEXT_SIBLING] = g + PPR;
273
+ RegionMatrix[g + REGION_FIRST_CHILD] = -1;
274
+ RegionMatrix[g + REGION_MASS] = 0;
275
+ RegionMatrix[g + REGION_MASS_CENTER_X] = 0;
276
+ RegionMatrix[g + REGION_MASS_CENTER_Y] = 0;
277
+
278
+ // Top Right sub-region
279
+ g += PPR;
280
+ RegionMatrix[g + REGION_NODE] = -1;
281
+ RegionMatrix[g + REGION_CENTER_X] =
282
+ RegionMatrix[r + REGION_CENTER_X] + w;
283
+ RegionMatrix[g + REGION_CENTER_Y] =
284
+ RegionMatrix[r + REGION_CENTER_Y] - w;
285
+ RegionMatrix[g + REGION_SIZE] = w;
286
+ RegionMatrix[g + REGION_NEXT_SIBLING] = g + PPR;
287
+ RegionMatrix[g + REGION_FIRST_CHILD] = -1;
288
+ RegionMatrix[g + REGION_MASS] = 0;
289
+ RegionMatrix[g + REGION_MASS_CENTER_X] = 0;
290
+ RegionMatrix[g + REGION_MASS_CENTER_Y] = 0;
291
+
292
+ // Bottom Right sub-region
293
+ g += PPR;
294
+ RegionMatrix[g + REGION_NODE] = -1;
295
+ RegionMatrix[g + REGION_CENTER_X] =
296
+ RegionMatrix[r + REGION_CENTER_X] + w;
297
+ RegionMatrix[g + REGION_CENTER_Y] =
298
+ RegionMatrix[r + REGION_CENTER_Y] + w;
299
+ RegionMatrix[g + REGION_SIZE] = w;
300
+ RegionMatrix[g + REGION_NEXT_SIBLING] =
301
+ RegionMatrix[r + REGION_NEXT_SIBLING];
302
+ RegionMatrix[g + REGION_FIRST_CHILD] = -1;
303
+ RegionMatrix[g + REGION_MASS] = 0;
304
+ RegionMatrix[g + REGION_MASS_CENTER_X] = 0;
305
+ RegionMatrix[g + REGION_MASS_CENTER_Y] = 0;
306
+
307
+ l += 4;
308
+
309
+ // Now the goal is to find two different sub-regions
310
+ // for the two nodes: the one previously recorded (r[0])
311
+ // and the one we want to add (n)
312
+
313
+ // Find the quadrant of the old node
314
+ if (
315
+ NodeMatrix[RegionMatrix[r + REGION_NODE] + NODE_X] <
316
+ RegionMatrix[r + REGION_CENTER_X]
317
+ ) {
318
+ if (
319
+ NodeMatrix[RegionMatrix[r + REGION_NODE] + NODE_Y] <
320
+ RegionMatrix[r + REGION_CENTER_Y]
321
+ ) {
322
+ // Top Left quarter
323
+ q = RegionMatrix[r + REGION_FIRST_CHILD];
324
+ } else {
325
+ // Bottom Left quarter
326
+ q = RegionMatrix[r + REGION_FIRST_CHILD] + PPR;
327
+ }
328
+ } else {
329
+ if (
330
+ NodeMatrix[RegionMatrix[r + REGION_NODE] + NODE_Y] <
331
+ RegionMatrix[r + REGION_CENTER_Y]
332
+ ) {
333
+ // Top Right quarter
334
+ q = RegionMatrix[r + REGION_FIRST_CHILD] + PPR * 2;
335
+ } else {
336
+ // Bottom Right quarter
337
+ q = RegionMatrix[r + REGION_FIRST_CHILD] + PPR * 3;
338
+ }
339
+ }
340
+
341
+ // We remove r[0] from the region r, add its mass to r and record it in q
342
+ RegionMatrix[r + REGION_MASS] =
343
+ NodeMatrix[RegionMatrix[r + REGION_NODE] + NODE_MASS];
344
+ RegionMatrix[r + REGION_MASS_CENTER_X] =
345
+ NodeMatrix[RegionMatrix[r + REGION_NODE] + NODE_X];
346
+ RegionMatrix[r + REGION_MASS_CENTER_Y] =
347
+ NodeMatrix[RegionMatrix[r + REGION_NODE] + NODE_Y];
348
+
349
+ RegionMatrix[q + REGION_NODE] = RegionMatrix[r + REGION_NODE];
350
+ RegionMatrix[r + REGION_NODE] = -1;
351
+
352
+ // Find the quadrant of n
353
+ if (NodeMatrix[n + NODE_X] < RegionMatrix[r + REGION_CENTER_X]) {
354
+ if (NodeMatrix[n + NODE_Y] < RegionMatrix[r + REGION_CENTER_Y]) {
355
+ // Top Left quarter
356
+ q2 = RegionMatrix[r + REGION_FIRST_CHILD];
357
+ } else {
358
+ // Bottom Left quarter
359
+ q2 = RegionMatrix[r + REGION_FIRST_CHILD] + PPR;
360
+ }
361
+ } else {
362
+ if (NodeMatrix[n + NODE_Y] < RegionMatrix[r + REGION_CENTER_Y]) {
363
+ // Top Right quarter
364
+ q2 = RegionMatrix[r + REGION_FIRST_CHILD] + PPR * 2;
365
+ } else {
366
+ // Bottom Right quarter
367
+ q2 = RegionMatrix[r + REGION_FIRST_CHILD] + PPR * 3;
368
+ }
369
+ }
370
+
371
+ if (q === q2) {
372
+ // If both nodes are in the same quadrant,
373
+ // we have to try it again on this quadrant
374
+ if (subdivisionAttempts--) {
375
+ r = q;
376
+ continue; // while
377
+ } else {
378
+ // we are out of precision here, and we cannot subdivide anymore
379
+ // but we have to break the loop anyway
380
+ subdivisionAttempts = SUBDIVISION_ATTEMPTS;
381
+ break; // while
382
+ }
383
+ }
384
+
385
+ // If both quadrants are different, we record n
386
+ // in its quadrant
387
+ RegionMatrix[q2 + REGION_NODE] = n;
388
+ break;
389
+ }
390
+ }
391
+ }
392
+ }
393
+ }
394
+
395
+ // 2) Repulsion
396
+ //--------------
397
+ // NOTES: adjustSizes = antiCollision & scalingRatio = coefficient
398
+
399
+ if (options.barnesHutOptimize) {
400
+ coefficient = options.scalingRatio;
401
+
402
+ // Applying repulsion through regions
403
+ for (n = 0; n < order; n += PPN) {
404
+ // Computing leaf quad nodes iteration
405
+
406
+ r = 0; // Starting with root region
407
+ while (true) {
408
+ if (RegionMatrix[r + REGION_FIRST_CHILD] >= 0) {
409
+ // The region has sub-regions
410
+
411
+ // We run the Barnes Hut test to see if we are at the right distance
412
+ distance =
413
+ Math.pow(
414
+ NodeMatrix[n + NODE_X] - RegionMatrix[r + REGION_MASS_CENTER_X],
415
+ 2
416
+ ) +
417
+ Math.pow(
418
+ NodeMatrix[n + NODE_Y] - RegionMatrix[r + REGION_MASS_CENTER_Y],
419
+ 2
420
+ );
421
+
422
+ s = RegionMatrix[r + REGION_SIZE];
423
+
424
+ if ((4 * s * s) / distance < thetaSquared) {
425
+ // We treat the region as a single body, and we repulse
426
+
427
+ xDist =
428
+ NodeMatrix[n + NODE_X] - RegionMatrix[r + REGION_MASS_CENTER_X];
429
+ yDist =
430
+ NodeMatrix[n + NODE_Y] - RegionMatrix[r + REGION_MASS_CENTER_Y];
431
+
432
+ if (adjustSizes === true) {
433
+ //-- Linear Anti-collision Repulsion
434
+ if (distance > 0) {
435
+ factor =
436
+ (coefficient *
437
+ NodeMatrix[n + NODE_MASS] *
438
+ RegionMatrix[r + REGION_MASS]) /
439
+ distance;
440
+
441
+ NodeMatrix[n + NODE_DX] += xDist * factor;
442
+ NodeMatrix[n + NODE_DY] += yDist * factor;
443
+ } else if (distance < 0) {
444
+ factor =
445
+ (-coefficient *
446
+ NodeMatrix[n + NODE_MASS] *
447
+ RegionMatrix[r + REGION_MASS]) /
448
+ Math.sqrt(distance);
449
+
450
+ NodeMatrix[n + NODE_DX] += xDist * factor;
451
+ NodeMatrix[n + NODE_DY] += yDist * factor;
452
+ }
453
+ } else {
454
+ //-- Linear Repulsion
455
+ if (distance > 0) {
456
+ factor =
457
+ (coefficient *
458
+ NodeMatrix[n + NODE_MASS] *
459
+ RegionMatrix[r + REGION_MASS]) /
460
+ distance;
461
+
462
+ NodeMatrix[n + NODE_DX] += xDist * factor;
463
+ NodeMatrix[n + NODE_DY] += yDist * factor;
464
+ }
465
+ }
466
+
467
+ // When this is done, we iterate. We have to look at the next sibling.
468
+ r = RegionMatrix[r + REGION_NEXT_SIBLING];
469
+ if (r < 0) break; // No next sibling: we have finished the tree
470
+
471
+ continue;
472
+ } else {
473
+ // The region is too close and we have to look at sub-regions
474
+ r = RegionMatrix[r + REGION_FIRST_CHILD];
475
+ continue;
476
+ }
477
+ } else {
478
+ // The region has no sub-region
479
+ // If there is a node r[0] and it is not n, then repulse
480
+ rn = RegionMatrix[r + REGION_NODE];
481
+
482
+ if (rn >= 0 && rn !== n) {
483
+ xDist = NodeMatrix[n + NODE_X] - NodeMatrix[rn + NODE_X];
484
+ yDist = NodeMatrix[n + NODE_Y] - NodeMatrix[rn + NODE_Y];
485
+
486
+ distance = xDist * xDist + yDist * yDist;
487
+
488
+ if (adjustSizes === true) {
489
+ //-- Linear Anti-collision Repulsion
490
+ if (distance > 0) {
491
+ factor =
492
+ (coefficient *
493
+ NodeMatrix[n + NODE_MASS] *
494
+ NodeMatrix[rn + NODE_MASS]) /
495
+ distance;
496
+
497
+ NodeMatrix[n + NODE_DX] += xDist * factor;
498
+ NodeMatrix[n + NODE_DY] += yDist * factor;
499
+ } else if (distance < 0) {
500
+ factor =
501
+ (-coefficient *
502
+ NodeMatrix[n + NODE_MASS] *
503
+ NodeMatrix[rn + NODE_MASS]) /
504
+ Math.sqrt(distance);
505
+
506
+ NodeMatrix[n + NODE_DX] += xDist * factor;
507
+ NodeMatrix[n + NODE_DY] += yDist * factor;
508
+ }
509
+ } else {
510
+ //-- Linear Repulsion
511
+ if (distance > 0) {
512
+ factor =
513
+ (coefficient *
514
+ NodeMatrix[n + NODE_MASS] *
515
+ NodeMatrix[rn + NODE_MASS]) /
516
+ distance;
517
+
518
+ NodeMatrix[n + NODE_DX] += xDist * factor;
519
+ NodeMatrix[n + NODE_DY] += yDist * factor;
520
+ }
521
+ }
522
+ }
523
+
524
+ // When this is done, we iterate. We have to look at the next sibling.
525
+ r = RegionMatrix[r + REGION_NEXT_SIBLING];
526
+
527
+ if (r < 0) break; // No next sibling: we have finished the tree
528
+
529
+ continue;
530
+ }
531
+ }
532
+ }
533
+ } else {
534
+ coefficient = options.scalingRatio;
535
+
536
+ // Square iteration
537
+ for (n1 = 0; n1 < order; n1 += PPN) {
538
+ for (n2 = 0; n2 < n1; n2 += PPN) {
539
+ // Common to both methods
540
+ xDist = NodeMatrix[n1 + NODE_X] - NodeMatrix[n2 + NODE_X];
541
+ yDist = NodeMatrix[n1 + NODE_Y] - NodeMatrix[n2 + NODE_Y];
542
+
543
+ if (adjustSizes === true) {
544
+ //-- Anticollision Linear Repulsion
545
+ distance =
546
+ Math.sqrt(xDist * xDist + yDist * yDist) -
547
+ NodeMatrix[n1 + NODE_SIZE] -
548
+ NodeMatrix[n2 + NODE_SIZE];
549
+
550
+ if (distance > 0) {
551
+ factor =
552
+ (coefficient *
553
+ NodeMatrix[n1 + NODE_MASS] *
554
+ NodeMatrix[n2 + NODE_MASS]) /
555
+ distance /
556
+ distance;
557
+
558
+ // Updating nodes' dx and dy
559
+ NodeMatrix[n1 + NODE_DX] += xDist * factor;
560
+ NodeMatrix[n1 + NODE_DY] += yDist * factor;
561
+
562
+ NodeMatrix[n2 + NODE_DX] -= xDist * factor;
563
+ NodeMatrix[n2 + NODE_DY] -= yDist * factor;
564
+ } else if (distance < 0) {
565
+ factor =
566
+ 100 *
567
+ coefficient *
568
+ NodeMatrix[n1 + NODE_MASS] *
569
+ NodeMatrix[n2 + NODE_MASS];
570
+
571
+ // Updating nodes' dx and dy
572
+ NodeMatrix[n1 + NODE_DX] += xDist * factor;
573
+ NodeMatrix[n1 + NODE_DY] += yDist * factor;
574
+
575
+ NodeMatrix[n2 + NODE_DX] -= xDist * factor;
576
+ NodeMatrix[n2 + NODE_DY] -= yDist * factor;
577
+ }
578
+ } else {
579
+ //-- Linear Repulsion
580
+ distance = Math.sqrt(xDist * xDist + yDist * yDist);
581
+
582
+ if (distance > 0) {
583
+ factor =
584
+ (coefficient *
585
+ NodeMatrix[n1 + NODE_MASS] *
586
+ NodeMatrix[n2 + NODE_MASS]) /
587
+ distance /
588
+ distance;
589
+
590
+ // Updating nodes' dx and dy
591
+ NodeMatrix[n1 + NODE_DX] += xDist * factor;
592
+ NodeMatrix[n1 + NODE_DY] += yDist * factor;
593
+
594
+ NodeMatrix[n2 + NODE_DX] -= xDist * factor;
595
+ NodeMatrix[n2 + NODE_DY] -= yDist * factor;
596
+ }
597
+ }
598
+ }
599
+ }
600
+ }
601
+
602
+ // 3) Gravity
603
+ //------------
604
+ g = options.gravity / options.scalingRatio;
605
+ coefficient = options.scalingRatio;
606
+ for (n = 0; n < order; n += PPN) {
607
+ factor = 0;
608
+
609
+ // Common to both methods
610
+ xDist = NodeMatrix[n + NODE_X];
611
+ yDist = NodeMatrix[n + NODE_Y];
612
+ distance = Math.sqrt(Math.pow(xDist, 2) + Math.pow(yDist, 2));
613
+
614
+ if (options.strongGravityMode) {
615
+ //-- Strong gravity
616
+ if (distance > 0) factor = coefficient * NodeMatrix[n + NODE_MASS] * g;
617
+ } else {
618
+ //-- Linear Anti-collision Repulsion n
619
+ if (distance > 0)
620
+ factor = (coefficient * NodeMatrix[n + NODE_MASS] * g) / distance;
621
+ }
622
+
623
+ // Updating node's dx and dy
624
+ NodeMatrix[n + NODE_DX] -= xDist * factor;
625
+ NodeMatrix[n + NODE_DY] -= yDist * factor;
626
+ }
627
+
628
+ // 4) Attraction
629
+ //---------------
630
+ coefficient =
631
+ 1 * (options.outboundAttractionDistribution ? outboundAttCompensation : 1);
632
+
633
+ // TODO: simplify distance
634
+ // TODO: coefficient is always used as -c --> optimize?
635
+ for (e = 0; e < size; e += PPE) {
636
+ n1 = EdgeMatrix[e + EDGE_SOURCE];
637
+ n2 = EdgeMatrix[e + EDGE_TARGET];
638
+ w = EdgeMatrix[e + EDGE_WEIGHT];
639
+
640
+ // Edge weight influence
641
+ ewc = Math.pow(w, options.edgeWeightInfluence);
642
+
643
+ // Common measures
644
+ xDist = NodeMatrix[n1 + NODE_X] - NodeMatrix[n2 + NODE_X];
645
+ yDist = NodeMatrix[n1 + NODE_Y] - NodeMatrix[n2 + NODE_Y];
646
+
647
+ // Applying attraction to nodes
648
+ if (adjustSizes === true) {
649
+ distance =
650
+ Math.sqrt(xDist * xDist + yDist * yDist) -
651
+ NodeMatrix[n1 + NODE_SIZE] -
652
+ NodeMatrix[n2 + NODE_SIZE];
653
+
654
+ if (options.linLogMode) {
655
+ if (options.outboundAttractionDistribution) {
656
+ //-- LinLog Degree Distributed Anti-collision Attraction
657
+ if (distance > 0) {
658
+ factor =
659
+ (-coefficient * ewc * Math.log(1 + distance)) /
660
+ distance /
661
+ NodeMatrix[n1 + NODE_MASS];
662
+ }
663
+ } else {
664
+ //-- LinLog Anti-collision Attraction
665
+ if (distance > 0) {
666
+ factor = (-coefficient * ewc * Math.log(1 + distance)) / distance;
667
+ }
668
+ }
669
+ } else {
670
+ if (options.outboundAttractionDistribution) {
671
+ //-- Linear Degree Distributed Anti-collision Attraction
672
+ if (distance > 0) {
673
+ factor = (-coefficient * ewc) / NodeMatrix[n1 + NODE_MASS];
674
+ }
675
+ } else {
676
+ //-- Linear Anti-collision Attraction
677
+ if (distance > 0) {
678
+ factor = -coefficient * ewc;
679
+ }
680
+ }
681
+ }
682
+ } else {
683
+ distance = Math.sqrt(Math.pow(xDist, 2) + Math.pow(yDist, 2));
684
+
685
+ if (options.linLogMode) {
686
+ if (options.outboundAttractionDistribution) {
687
+ //-- LinLog Degree Distributed Attraction
688
+ if (distance > 0) {
689
+ factor =
690
+ (-coefficient * ewc * Math.log(1 + distance)) /
691
+ distance /
692
+ NodeMatrix[n1 + NODE_MASS];
693
+ }
694
+ } else {
695
+ //-- LinLog Attraction
696
+ if (distance > 0)
697
+ factor = (-coefficient * ewc * Math.log(1 + distance)) / distance;
698
+ }
699
+ } else {
700
+ if (options.outboundAttractionDistribution) {
701
+ //-- Linear Attraction Mass Distributed
702
+ // NOTE: Distance is set to 1 to override next condition
703
+ distance = 1;
704
+ factor = (-coefficient * ewc) / NodeMatrix[n1 + NODE_MASS];
705
+ } else {
706
+ //-- Linear Attraction
707
+ // NOTE: Distance is set to 1 to override next condition
708
+ distance = 1;
709
+ factor = -coefficient * ewc;
710
+ }
711
+ }
712
+ }
713
+
714
+ // Updating nodes' dx and dy
715
+ // TODO: if condition or factor = 1?
716
+ if (distance > 0) {
717
+ // Updating nodes' dx and dy
718
+ NodeMatrix[n1 + NODE_DX] += xDist * factor;
719
+ NodeMatrix[n1 + NODE_DY] += yDist * factor;
720
+
721
+ NodeMatrix[n2 + NODE_DX] -= xDist * factor;
722
+ NodeMatrix[n2 + NODE_DY] -= yDist * factor;
723
+ }
724
+ }
725
+
726
+ // 5) Apply Forces
727
+ //-----------------
728
+ var force, swinging, traction, nodespeed, newX, newY;
729
+
730
+ // MATH: sqrt and square distances
731
+ if (adjustSizes === true) {
732
+ for (n = 0; n < order; n += PPN) {
733
+ if (NodeMatrix[n + NODE_FIXED] !== 1) {
734
+ force = Math.sqrt(
735
+ Math.pow(NodeMatrix[n + NODE_DX], 2) +
736
+ Math.pow(NodeMatrix[n + NODE_DY], 2)
737
+ );
738
+
739
+ if (force > MAX_FORCE) {
740
+ NodeMatrix[n + NODE_DX] =
741
+ (NodeMatrix[n + NODE_DX] * MAX_FORCE) / force;
742
+ NodeMatrix[n + NODE_DY] =
743
+ (NodeMatrix[n + NODE_DY] * MAX_FORCE) / force;
744
+ }
745
+
746
+ swinging =
747
+ NodeMatrix[n + NODE_MASS] *
748
+ Math.sqrt(
749
+ (NodeMatrix[n + NODE_OLD_DX] - NodeMatrix[n + NODE_DX]) *
750
+ (NodeMatrix[n + NODE_OLD_DX] - NodeMatrix[n + NODE_DX]) +
751
+ (NodeMatrix[n + NODE_OLD_DY] - NodeMatrix[n + NODE_DY]) *
752
+ (NodeMatrix[n + NODE_OLD_DY] - NodeMatrix[n + NODE_DY])
753
+ );
754
+
755
+ traction =
756
+ Math.sqrt(
757
+ (NodeMatrix[n + NODE_OLD_DX] + NodeMatrix[n + NODE_DX]) *
758
+ (NodeMatrix[n + NODE_OLD_DX] + NodeMatrix[n + NODE_DX]) +
759
+ (NodeMatrix[n + NODE_OLD_DY] + NodeMatrix[n + NODE_DY]) *
760
+ (NodeMatrix[n + NODE_OLD_DY] + NodeMatrix[n + NODE_DY])
761
+ ) / 2;
762
+
763
+ nodespeed = (0.1 * Math.log(1 + traction)) / (1 + Math.sqrt(swinging));
764
+
765
+ // Updating node's positon
766
+ newX =
767
+ NodeMatrix[n + NODE_X] +
768
+ NodeMatrix[n + NODE_DX] * (nodespeed / options.slowDown);
769
+ NodeMatrix[n + NODE_X] = newX;
770
+
771
+ newY =
772
+ NodeMatrix[n + NODE_Y] +
773
+ NodeMatrix[n + NODE_DY] * (nodespeed / options.slowDown);
774
+ NodeMatrix[n + NODE_Y] = newY;
775
+ }
776
+ }
777
+ } else {
778
+ for (n = 0; n < order; n += PPN) {
779
+ if (NodeMatrix[n + NODE_FIXED] !== 1) {
780
+ swinging =
781
+ NodeMatrix[n + NODE_MASS] *
782
+ Math.sqrt(
783
+ (NodeMatrix[n + NODE_OLD_DX] - NodeMatrix[n + NODE_DX]) *
784
+ (NodeMatrix[n + NODE_OLD_DX] - NodeMatrix[n + NODE_DX]) +
785
+ (NodeMatrix[n + NODE_OLD_DY] - NodeMatrix[n + NODE_DY]) *
786
+ (NodeMatrix[n + NODE_OLD_DY] - NodeMatrix[n + NODE_DY])
787
+ );
788
+
789
+ traction =
790
+ Math.sqrt(
791
+ (NodeMatrix[n + NODE_OLD_DX] + NodeMatrix[n + NODE_DX]) *
792
+ (NodeMatrix[n + NODE_OLD_DX] + NodeMatrix[n + NODE_DX]) +
793
+ (NodeMatrix[n + NODE_OLD_DY] + NodeMatrix[n + NODE_DY]) *
794
+ (NodeMatrix[n + NODE_OLD_DY] + NodeMatrix[n + NODE_DY])
795
+ ) / 2;
796
+
797
+ nodespeed =
798
+ (NodeMatrix[n + NODE_CONVERGENCE] * Math.log(1 + traction)) /
799
+ (1 + Math.sqrt(swinging));
800
+
801
+ // Updating node convergence
802
+ NodeMatrix[n + NODE_CONVERGENCE] = Math.min(
803
+ 1,
804
+ Math.sqrt(
805
+ (nodespeed *
806
+ (Math.pow(NodeMatrix[n + NODE_DX], 2) +
807
+ Math.pow(NodeMatrix[n + NODE_DY], 2))) /
808
+ (1 + Math.sqrt(swinging))
809
+ )
810
+ );
811
+
812
+ // Updating node's positon
813
+ newX =
814
+ NodeMatrix[n + NODE_X] +
815
+ NodeMatrix[n + NODE_DX] * (nodespeed / options.slowDown);
816
+ NodeMatrix[n + NODE_X] = newX;
817
+
818
+ newY =
819
+ NodeMatrix[n + NODE_Y] +
820
+ NodeMatrix[n + NODE_DY] * (nodespeed / options.slowDown);
821
+ NodeMatrix[n + NODE_Y] = newY;
822
+ }
823
+ }
824
+ }
825
+
826
+ // We return the information about the layout (no need to return the matrices)
827
+ return {};
828
+ };
829
+
830
+ })();
831
+
832
+ var iterate = moduleShim.exports;
833
+
834
+ self.addEventListener('message', function (event) {
835
+ var data = event.data;
836
+
837
+ NODES = new Float32Array(data.nodes);
838
+
839
+ if (data.edges) EDGES = new Float32Array(data.edges);
840
+
841
+ // Running the iteration
842
+ iterate(data.settings, NODES, EDGES);
843
+
844
+ // Sending result to supervisor
845
+ self.postMessage(
846
+ {
847
+ nodes: NODES.buffer
848
+ },
849
+ [NODES.buffer]
850
+ );
851
+ });
852
+ };
853
+ return webworker;
854
+ }
855
+
856
+ /**
857
+ * Graphology isGraph
858
+ * ===================
859
+ *
860
+ * Very simple function aiming at ensuring the given variable is a
861
+ * graphology instance.
862
+ */
863
+
864
+ var isGraph;
865
+ var hasRequiredIsGraph;
866
+
867
+ function requireIsGraph () {
868
+ if (hasRequiredIsGraph) return isGraph;
869
+ hasRequiredIsGraph = 1;
870
+ /**
871
+ * Checking the value is a graphology instance.
872
+ *
873
+ * @param {any} value - Target value.
874
+ * @return {boolean}
875
+ */
876
+ isGraph = function isGraph(value) {
877
+ return (
878
+ value !== null &&
879
+ typeof value === 'object' &&
880
+ typeof value.addUndirectedEdgeWithKey === 'function' &&
881
+ typeof value.dropNode === 'function' &&
882
+ typeof value.multi === 'boolean'
883
+ );
884
+ };
885
+ return isGraph;
886
+ }
887
+
888
+ var getters = {};
889
+
890
+ /**
891
+ * Graphology Weight Getter
892
+ * =========================
893
+ *
894
+ * Function creating weight getters.
895
+ */
896
+
897
+ var hasRequiredGetters;
898
+
899
+ function requireGetters () {
900
+ if (hasRequiredGetters) return getters;
901
+ hasRequiredGetters = 1;
902
+ function coerceWeight(value) {
903
+ // Ensuring target value is a correct number
904
+ if (typeof value !== 'number' || isNaN(value)) return 1;
905
+
906
+ return value;
907
+ }
908
+
909
+ function createNodeValueGetter(nameOrFunction, defaultValue) {
910
+ var getter = {};
911
+
912
+ var coerceToDefault = function (v) {
913
+ if (typeof v === 'undefined') return defaultValue;
914
+
915
+ return v;
916
+ };
917
+
918
+ if (typeof defaultValue === 'function') coerceToDefault = defaultValue;
919
+
920
+ var get = function (attributes) {
921
+ return coerceToDefault(attributes[nameOrFunction]);
922
+ };
923
+
924
+ var returnDefault = function () {
925
+ return coerceToDefault(undefined);
926
+ };
927
+
928
+ if (typeof nameOrFunction === 'string') {
929
+ getter.fromAttributes = get;
930
+ getter.fromGraph = function (graph, node) {
931
+ return get(graph.getNodeAttributes(node));
932
+ };
933
+ getter.fromEntry = function (node, attributes) {
934
+ return get(attributes);
935
+ };
936
+ } else if (typeof nameOrFunction === 'function') {
937
+ getter.fromAttributes = function () {
938
+ throw new Error(
939
+ 'graphology-utils/getters/createNodeValueGetter: irrelevant usage.'
940
+ );
941
+ };
942
+ getter.fromGraph = function (graph, node) {
943
+ return coerceToDefault(
944
+ nameOrFunction(node, graph.getNodeAttributes(node))
945
+ );
946
+ };
947
+ getter.fromEntry = function (node, attributes) {
948
+ return coerceToDefault(nameOrFunction(node, attributes));
949
+ };
950
+ } else {
951
+ getter.fromAttributes = returnDefault;
952
+ getter.fromGraph = returnDefault;
953
+ getter.fromEntry = returnDefault;
954
+ }
955
+
956
+ return getter;
957
+ }
958
+
959
+ function createEdgeValueGetter(nameOrFunction, defaultValue) {
960
+ var getter = {};
961
+
962
+ var coerceToDefault = function (v) {
963
+ if (typeof v === 'undefined') return defaultValue;
964
+
965
+ return v;
966
+ };
967
+
968
+ if (typeof defaultValue === 'function') coerceToDefault = defaultValue;
969
+
970
+ var get = function (attributes) {
971
+ return coerceToDefault(attributes[nameOrFunction]);
972
+ };
973
+
974
+ var returnDefault = function () {
975
+ return coerceToDefault(undefined);
976
+ };
977
+
978
+ if (typeof nameOrFunction === 'string') {
979
+ getter.fromAttributes = get;
980
+ getter.fromGraph = function (graph, edge) {
981
+ return get(graph.getEdgeAttributes(edge));
982
+ };
983
+ getter.fromEntry = function (edge, attributes) {
984
+ return get(attributes);
985
+ };
986
+ getter.fromPartialEntry = getter.fromEntry;
987
+ getter.fromMinimalEntry = getter.fromEntry;
988
+ } else if (typeof nameOrFunction === 'function') {
989
+ getter.fromAttributes = function () {
990
+ throw new Error(
991
+ 'graphology-utils/getters/createEdgeValueGetter: irrelevant usage.'
992
+ );
993
+ };
994
+ getter.fromGraph = function (graph, edge) {
995
+ // TODO: we can do better, check #310
996
+ var extremities = graph.extremities(edge);
997
+ return coerceToDefault(
998
+ nameOrFunction(
999
+ edge,
1000
+ graph.getEdgeAttributes(edge),
1001
+ extremities[0],
1002
+ extremities[1],
1003
+ graph.getNodeAttributes(extremities[0]),
1004
+ graph.getNodeAttributes(extremities[1]),
1005
+ graph.isUndirected(edge)
1006
+ )
1007
+ );
1008
+ };
1009
+ getter.fromEntry = function (e, a, s, t, sa, ta, u) {
1010
+ return coerceToDefault(nameOrFunction(e, a, s, t, sa, ta, u));
1011
+ };
1012
+ getter.fromPartialEntry = function (e, a, s, t) {
1013
+ return coerceToDefault(nameOrFunction(e, a, s, t));
1014
+ };
1015
+ getter.fromMinimalEntry = function (e, a) {
1016
+ return coerceToDefault(nameOrFunction(e, a));
1017
+ };
1018
+ } else {
1019
+ getter.fromAttributes = returnDefault;
1020
+ getter.fromGraph = returnDefault;
1021
+ getter.fromEntry = returnDefault;
1022
+ getter.fromMinimalEntry = returnDefault;
1023
+ }
1024
+
1025
+ return getter;
1026
+ }
1027
+
1028
+ getters.createNodeValueGetter = createNodeValueGetter;
1029
+ getters.createEdgeValueGetter = createEdgeValueGetter;
1030
+ getters.createEdgeWeightGetter = function (name) {
1031
+ return createEdgeValueGetter(name, coerceWeight);
1032
+ };
1033
+ return getters;
1034
+ }
1035
+
1036
+ var helpers = {};
1037
+
1038
+ /**
1039
+ * Graphology ForceAtlas2 Helpers
1040
+ * ===============================
1041
+ *
1042
+ * Miscellaneous helper functions.
1043
+ */
1044
+
1045
+ var hasRequiredHelpers;
1046
+
1047
+ function requireHelpers () {
1048
+ if (hasRequiredHelpers) return helpers;
1049
+ hasRequiredHelpers = 1;
1050
+ /**
1051
+ * Constants.
1052
+ */
1053
+ var PPN = 10;
1054
+ var PPE = 3;
1055
+
1056
+ /**
1057
+ * Very simple Object.assign-like function.
1058
+ *
1059
+ * @param {object} target - First object.
1060
+ * @param {object} [...objects] - Objects to merge.
1061
+ * @return {object}
1062
+ */
1063
+ helpers.assign = function (target) {
1064
+ target = target || {};
1065
+
1066
+ var objects = Array.prototype.slice.call(arguments).slice(1),
1067
+ i,
1068
+ k,
1069
+ l;
1070
+
1071
+ for (i = 0, l = objects.length; i < l; i++) {
1072
+ if (!objects[i]) continue;
1073
+
1074
+ for (k in objects[i]) target[k] = objects[i][k];
1075
+ }
1076
+
1077
+ return target;
1078
+ };
1079
+
1080
+ /**
1081
+ * Function used to validate the given settings.
1082
+ *
1083
+ * @param {object} settings - Settings to validate.
1084
+ * @return {object|null}
1085
+ */
1086
+ helpers.validateSettings = function (settings) {
1087
+ if ('linLogMode' in settings && typeof settings.linLogMode !== 'boolean')
1088
+ return {message: 'the `linLogMode` setting should be a boolean.'};
1089
+
1090
+ if (
1091
+ 'outboundAttractionDistribution' in settings &&
1092
+ typeof settings.outboundAttractionDistribution !== 'boolean'
1093
+ )
1094
+ return {
1095
+ message:
1096
+ 'the `outboundAttractionDistribution` setting should be a boolean.'
1097
+ };
1098
+
1099
+ if ('adjustSizes' in settings && typeof settings.adjustSizes !== 'boolean')
1100
+ return {message: 'the `adjustSizes` setting should be a boolean.'};
1101
+
1102
+ if (
1103
+ 'edgeWeightInfluence' in settings &&
1104
+ typeof settings.edgeWeightInfluence !== 'number'
1105
+ )
1106
+ return {
1107
+ message: 'the `edgeWeightInfluence` setting should be a number.'
1108
+ };
1109
+
1110
+ if (
1111
+ 'scalingRatio' in settings &&
1112
+ !(typeof settings.scalingRatio === 'number' && settings.scalingRatio >= 0)
1113
+ )
1114
+ return {message: 'the `scalingRatio` setting should be a number >= 0.'};
1115
+
1116
+ if (
1117
+ 'strongGravityMode' in settings &&
1118
+ typeof settings.strongGravityMode !== 'boolean'
1119
+ )
1120
+ return {message: 'the `strongGravityMode` setting should be a boolean.'};
1121
+
1122
+ if (
1123
+ 'gravity' in settings &&
1124
+ !(typeof settings.gravity === 'number' && settings.gravity >= 0)
1125
+ )
1126
+ return {message: 'the `gravity` setting should be a number >= 0.'};
1127
+
1128
+ if (
1129
+ 'slowDown' in settings &&
1130
+ !(typeof settings.slowDown === 'number' || settings.slowDown >= 0)
1131
+ )
1132
+ return {message: 'the `slowDown` setting should be a number >= 0.'};
1133
+
1134
+ if (
1135
+ 'barnesHutOptimize' in settings &&
1136
+ typeof settings.barnesHutOptimize !== 'boolean'
1137
+ )
1138
+ return {message: 'the `barnesHutOptimize` setting should be a boolean.'};
1139
+
1140
+ if (
1141
+ 'barnesHutTheta' in settings &&
1142
+ !(
1143
+ typeof settings.barnesHutTheta === 'number' &&
1144
+ settings.barnesHutTheta >= 0
1145
+ )
1146
+ )
1147
+ return {message: 'the `barnesHutTheta` setting should be a number >= 0.'};
1148
+
1149
+ return null;
1150
+ };
1151
+
1152
+ /**
1153
+ * Function generating a flat matrix for both nodes & edges of the given graph.
1154
+ *
1155
+ * @param {Graph} graph - Target graph.
1156
+ * @param {function} getEdgeWeight - Edge weight getter function.
1157
+ * @return {object} - Both matrices.
1158
+ */
1159
+ helpers.graphToByteArrays = function (graph, getEdgeWeight) {
1160
+ var order = graph.order;
1161
+ var size = graph.size;
1162
+ var index = {};
1163
+ var j;
1164
+
1165
+ // NOTE: float32 could lead to issues if edge array needs to index large
1166
+ // number of nodes.
1167
+ var NodeMatrix = new Float32Array(order * PPN);
1168
+ var EdgeMatrix = new Float32Array(size * PPE);
1169
+
1170
+ // Iterate through nodes
1171
+ j = 0;
1172
+ graph.forEachNode(function (node, attr) {
1173
+ // Node index
1174
+ index[node] = j;
1175
+
1176
+ // Populating byte array
1177
+ NodeMatrix[j] = attr.x;
1178
+ NodeMatrix[j + 1] = attr.y;
1179
+ NodeMatrix[j + 2] = 0; // dx
1180
+ NodeMatrix[j + 3] = 0; // dy
1181
+ NodeMatrix[j + 4] = 0; // old_dx
1182
+ NodeMatrix[j + 5] = 0; // old_dy
1183
+ NodeMatrix[j + 6] = 1; // mass
1184
+ NodeMatrix[j + 7] = 1; // convergence
1185
+ NodeMatrix[j + 8] = attr.size || 1;
1186
+ NodeMatrix[j + 9] = attr.fixed ? 1 : 0;
1187
+ j += PPN;
1188
+ });
1189
+
1190
+ // Iterate through edges
1191
+ j = 0;
1192
+ graph.forEachEdge(function (edge, attr, source, target, sa, ta, u) {
1193
+ var sj = index[source];
1194
+ var tj = index[target];
1195
+
1196
+ var weight = getEdgeWeight(edge, attr, source, target, sa, ta, u);
1197
+
1198
+ // Incrementing mass to be a node's weighted degree
1199
+ NodeMatrix[sj + 6] += weight;
1200
+ NodeMatrix[tj + 6] += weight;
1201
+
1202
+ // Populating byte array
1203
+ EdgeMatrix[j] = sj;
1204
+ EdgeMatrix[j + 1] = tj;
1205
+ EdgeMatrix[j + 2] = weight;
1206
+ j += PPE;
1207
+ });
1208
+
1209
+ return {
1210
+ nodes: NodeMatrix,
1211
+ edges: EdgeMatrix
1212
+ };
1213
+ };
1214
+
1215
+ /**
1216
+ * Function applying the layout back to the graph.
1217
+ *
1218
+ * @param {Graph} graph - Target graph.
1219
+ * @param {Float32Array} NodeMatrix - Node matrix.
1220
+ * @param {function|null} outputReducer - A node reducer.
1221
+ */
1222
+ helpers.assignLayoutChanges = function (graph, NodeMatrix, outputReducer) {
1223
+ var i = 0;
1224
+
1225
+ graph.updateEachNodeAttributes(function (node, attr) {
1226
+ attr.x = NodeMatrix[i];
1227
+ attr.y = NodeMatrix[i + 1];
1228
+
1229
+ i += PPN;
1230
+
1231
+ return outputReducer ? outputReducer(node, attr) : attr;
1232
+ });
1233
+ };
1234
+
1235
+ /**
1236
+ * Function reading the positions (only) from the graph, to write them in the matrix.
1237
+ *
1238
+ * @param {Graph} graph - Target graph.
1239
+ * @param {Float32Array} NodeMatrix - Node matrix.
1240
+ */
1241
+ helpers.readGraphPositions = function (graph, NodeMatrix) {
1242
+ var i = 0;
1243
+
1244
+ graph.forEachNode(function (node, attr) {
1245
+ NodeMatrix[i] = attr.x;
1246
+ NodeMatrix[i + 1] = attr.y;
1247
+
1248
+ i += PPN;
1249
+ });
1250
+ };
1251
+
1252
+ /**
1253
+ * Function collecting the layout positions.
1254
+ *
1255
+ * @param {Graph} graph - Target graph.
1256
+ * @param {Float32Array} NodeMatrix - Node matrix.
1257
+ * @param {function|null} outputReducer - A nodes reducer.
1258
+ * @return {object} - Map to node positions.
1259
+ */
1260
+ helpers.collectLayoutChanges = function (graph, NodeMatrix, outputReducer) {
1261
+ var nodes = graph.nodes(),
1262
+ positions = {};
1263
+
1264
+ for (var i = 0, j = 0, l = NodeMatrix.length; i < l; i += PPN) {
1265
+ if (outputReducer) {
1266
+ var newAttr = Object.assign({}, graph.getNodeAttributes(nodes[j]));
1267
+ newAttr.x = NodeMatrix[i];
1268
+ newAttr.y = NodeMatrix[i + 1];
1269
+ newAttr = outputReducer(nodes[j], newAttr);
1270
+ positions[nodes[j]] = {
1271
+ x: newAttr.x,
1272
+ y: newAttr.y
1273
+ };
1274
+ } else {
1275
+ positions[nodes[j]] = {
1276
+ x: NodeMatrix[i],
1277
+ y: NodeMatrix[i + 1]
1278
+ };
1279
+ }
1280
+
1281
+ j++;
1282
+ }
1283
+
1284
+ return positions;
1285
+ };
1286
+
1287
+ /**
1288
+ * Function returning a web worker from the given function.
1289
+ *
1290
+ * @param {function} fn - Function for the worker.
1291
+ * @return {DOMString}
1292
+ */
1293
+ helpers.createWorker = function createWorker(fn) {
1294
+ var xURL = window.URL || window.webkitURL;
1295
+ var code = fn.toString();
1296
+ var objectUrl = xURL.createObjectURL(
1297
+ new Blob(['(' + code + ').call(this);'], {type: 'text/javascript'})
1298
+ );
1299
+ var worker = new Worker(objectUrl);
1300
+ xURL.revokeObjectURL(objectUrl);
1301
+
1302
+ return worker;
1303
+ };
1304
+ return helpers;
1305
+ }
1306
+
1307
+ /**
1308
+ * Graphology ForceAtlas2 Layout Default Settings
1309
+ * ===============================================
1310
+ */
1311
+
1312
+ var defaults;
1313
+ var hasRequiredDefaults;
1314
+
1315
+ function requireDefaults () {
1316
+ if (hasRequiredDefaults) return defaults;
1317
+ hasRequiredDefaults = 1;
1318
+ defaults = {
1319
+ linLogMode: false,
1320
+ outboundAttractionDistribution: false,
1321
+ adjustSizes: false,
1322
+ edgeWeightInfluence: 1,
1323
+ scalingRatio: 1,
1324
+ strongGravityMode: false,
1325
+ gravity: 1,
1326
+ slowDown: 1,
1327
+ barnesHutOptimize: false,
1328
+ barnesHutTheta: 0.5
1329
+ };
1330
+ return defaults;
1331
+ }
1332
+
1333
+ /**
1334
+ * Graphology ForceAtlas2 Layout Supervisor
1335
+ * =========================================
1336
+ *
1337
+ * Supervisor class able to spawn a web worker to run the FA2 layout in a
1338
+ * separate thread not to block UI with heavy synchronous computations.
1339
+ */
1340
+
1341
+ var worker;
1342
+ var hasRequiredWorker;
1343
+
1344
+ function requireWorker () {
1345
+ if (hasRequiredWorker) return worker;
1346
+ hasRequiredWorker = 1;
1347
+ var workerFunction = requireWebworker();
1348
+ var isGraph = requireIsGraph();
1349
+ var createEdgeWeightGetter =
1350
+ requireGetters().createEdgeWeightGetter;
1351
+ var helpers = requireHelpers();
1352
+
1353
+ var DEFAULT_SETTINGS = requireDefaults();
1354
+
1355
+ /**
1356
+ * Class representing a FA2 layout run by a webworker.
1357
+ *
1358
+ * @constructor
1359
+ * @param {Graph} graph - Target graph.
1360
+ * @param {object|number} params - Parameters:
1361
+ * @param {object} [settings] - Settings.
1362
+ */
1363
+ function FA2LayoutSupervisor(graph, params) {
1364
+ params = params || {};
1365
+
1366
+ // Validation
1367
+ if (!isGraph(graph))
1368
+ throw new Error(
1369
+ 'graphology-layout-forceatlas2/worker: the given graph is not a valid graphology instance.'
1370
+ );
1371
+
1372
+ var getEdgeWeight = createEdgeWeightGetter(
1373
+ 'getEdgeWeight' in params ? params.getEdgeWeight : 'weight'
1374
+ ).fromEntry;
1375
+
1376
+ // Validating settings
1377
+ var settings = helpers.assign({}, DEFAULT_SETTINGS, params.settings);
1378
+ var validationError = helpers.validateSettings(settings);
1379
+
1380
+ if (validationError)
1381
+ throw new Error(
1382
+ 'graphology-layout-forceatlas2/worker: ' + validationError.message
1383
+ );
1384
+
1385
+ // Properties
1386
+ this.worker = null;
1387
+ this.graph = graph;
1388
+ this.settings = settings;
1389
+ this.getEdgeWeight = getEdgeWeight;
1390
+ this.matrices = null;
1391
+ this.running = false;
1392
+ this.killed = false;
1393
+ this.outputReducer =
1394
+ typeof params.outputReducer === 'function' ? params.outputReducer : null;
1395
+
1396
+ // Binding listeners
1397
+ this.handleMessage = this.handleMessage.bind(this);
1398
+
1399
+ var respawnFrame = undefined;
1400
+ var self = this;
1401
+
1402
+ this.handleGraphUpdate = function () {
1403
+ if (self.worker) self.worker.terminate();
1404
+
1405
+ if (respawnFrame) clearTimeout(respawnFrame);
1406
+
1407
+ respawnFrame = setTimeout(function () {
1408
+ respawnFrame = undefined;
1409
+ self.spawnWorker();
1410
+ }, 0);
1411
+ };
1412
+
1413
+ graph.on('nodeAdded', this.handleGraphUpdate);
1414
+ graph.on('edgeAdded', this.handleGraphUpdate);
1415
+ graph.on('nodeDropped', this.handleGraphUpdate);
1416
+ graph.on('edgeDropped', this.handleGraphUpdate);
1417
+
1418
+ // Spawning worker
1419
+ this.spawnWorker();
1420
+ }
1421
+
1422
+ FA2LayoutSupervisor.prototype.isRunning = function () {
1423
+ return this.running;
1424
+ };
1425
+
1426
+ /**
1427
+ * Internal method used to spawn the web worker.
1428
+ */
1429
+ FA2LayoutSupervisor.prototype.spawnWorker = function () {
1430
+ if (this.worker) this.worker.terminate();
1431
+
1432
+ this.worker = helpers.createWorker(workerFunction);
1433
+ this.worker.addEventListener('message', this.handleMessage);
1434
+
1435
+ if (this.running) {
1436
+ this.running = false;
1437
+ this.start();
1438
+ }
1439
+ };
1440
+
1441
+ /**
1442
+ * Internal method used to handle the worker's messages.
1443
+ *
1444
+ * @param {object} event - Event to handle.
1445
+ */
1446
+ FA2LayoutSupervisor.prototype.handleMessage = function (event) {
1447
+ if (!this.running) return;
1448
+
1449
+ var matrix = new Float32Array(event.data.nodes);
1450
+
1451
+ helpers.assignLayoutChanges(this.graph, matrix, this.outputReducer);
1452
+ if (this.outputReducer) helpers.readGraphPositions(this.graph, matrix);
1453
+ this.matrices.nodes = matrix;
1454
+
1455
+ // Looping
1456
+ this.askForIterations();
1457
+ };
1458
+
1459
+ /**
1460
+ * Internal method used to ask for iterations from the worker.
1461
+ *
1462
+ * @param {boolean} withEdges - Should we send edges along?
1463
+ * @return {FA2LayoutSupervisor}
1464
+ */
1465
+ FA2LayoutSupervisor.prototype.askForIterations = function (withEdges) {
1466
+ var matrices = this.matrices;
1467
+
1468
+ var payload = {
1469
+ settings: this.settings,
1470
+ nodes: matrices.nodes.buffer
1471
+ };
1472
+
1473
+ var buffers = [matrices.nodes.buffer];
1474
+
1475
+ if (withEdges) {
1476
+ payload.edges = matrices.edges.buffer;
1477
+ buffers.push(matrices.edges.buffer);
1478
+ }
1479
+
1480
+ this.worker.postMessage(payload, buffers);
1481
+
1482
+ return this;
1483
+ };
1484
+
1485
+ /**
1486
+ * Method used to start the layout.
1487
+ *
1488
+ * @return {FA2LayoutSupervisor}
1489
+ */
1490
+ FA2LayoutSupervisor.prototype.start = function () {
1491
+ if (this.killed)
1492
+ throw new Error(
1493
+ 'graphology-layout-forceatlas2/worker.start: layout was killed.'
1494
+ );
1495
+
1496
+ if (this.running) return this;
1497
+
1498
+ // Building matrices
1499
+ this.matrices = helpers.graphToByteArrays(this.graph, this.getEdgeWeight);
1500
+
1501
+ this.running = true;
1502
+ this.askForIterations(true);
1503
+
1504
+ return this;
1505
+ };
1506
+
1507
+ /**
1508
+ * Method used to stop the layout.
1509
+ *
1510
+ * @return {FA2LayoutSupervisor}
1511
+ */
1512
+ FA2LayoutSupervisor.prototype.stop = function () {
1513
+ this.running = false;
1514
+
1515
+ return this;
1516
+ };
1517
+
1518
+ /**
1519
+ * Method used to kill the layout.
1520
+ *
1521
+ * @return {FA2LayoutSupervisor}
1522
+ */
1523
+ FA2LayoutSupervisor.prototype.kill = function () {
1524
+ if (this.killed) return this;
1525
+
1526
+ this.running = false;
1527
+ this.killed = true;
1528
+
1529
+ // Clearing memory
1530
+ this.matrices = null;
1531
+
1532
+ // Terminating worker
1533
+ this.worker.terminate();
1534
+
1535
+ // Unbinding listeners
1536
+ this.graph.removeListener('nodeAdded', this.handleGraphUpdate);
1537
+ this.graph.removeListener('edgeAdded', this.handleGraphUpdate);
1538
+ this.graph.removeListener('nodeDropped', this.handleGraphUpdate);
1539
+ this.graph.removeListener('edgeDropped', this.handleGraphUpdate);
1540
+ };
1541
+
1542
+ /**
1543
+ * Exporting.
1544
+ */
1545
+ worker = FA2LayoutSupervisor;
1546
+ return worker;
1547
+ }
1548
+
1549
+ var workerExports = requireWorker();
1550
+ var FA2Layout = /*@__PURE__*/getDefaultExportFromCjs(workerExports);
1551
+
1552
+ const key = "vunk-graph-layout-forceatlas2";
1553
+ function initLayoutForceatlas2(props = {}) {
1554
+ const graph = useGraph();
1555
+ const layoutRef = shallowRef(null);
1556
+ function start() {
1557
+ const sensibleSettings = forceAtlas2.inferSettings(graph);
1558
+ layoutRef.value = new FA2Layout(graph, {
1559
+ settings: {
1560
+ ...sensibleSettings,
1561
+ ...props.settings
1562
+ }
1563
+ });
1564
+ layoutRef.value.start();
1565
+ }
1566
+ function stop() {
1567
+ layoutRef.value?.stop();
1568
+ }
1569
+ function kill() {
1570
+ layoutRef.value?.kill();
1571
+ }
1572
+ onBeforeUnmount(() => {
1573
+ layoutRef.value?.kill();
1574
+ });
1575
+ provide(key, {
1576
+ start,
1577
+ stop,
1578
+ kill,
1579
+ layoutRef
1580
+ });
1581
+ return {
1582
+ start,
1583
+ stop,
1584
+ kill
1585
+ };
1586
+ }
1587
+ function useLayoutForceatlas2() {
1588
+ const instance = inject(key);
1589
+ if (!instance) {
1590
+ throw new Error("useLayoutForceatlas2 must be used after provideLayoutForceatlas2");
1591
+ }
1592
+ return instance;
1593
+ }
1594
+
1595
+ var _sfc_main = defineComponent({
1596
+ name: "VkLayoutForceatlas2",
1597
+ props,
1598
+ setup(props2) {
1599
+ initLayoutForceatlas2(props2);
1600
+ return {};
1601
+ }
1602
+ });
1603
+
1604
+ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
1605
+ return renderSlot(_ctx.$slots, "default");
1606
+ }
1607
+ var VkLayoutForceatlas2 = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
1608
+
1609
+ var types = /*#__PURE__*/Object.freeze({
1610
+ __proto__: null
1611
+ });
1612
+
1613
+ VkLayoutForceatlas2.install = (app) => {
1614
+ app.component(VkLayoutForceatlas2.name || "VkLayoutForceatlas2", VkLayoutForceatlas2);
1615
+ };
1616
+
1617
+ export { VkLayoutForceatlas2, types as __VkLayoutForceatlas2, VkLayoutForceatlas2 as default, useLayoutForceatlas2 };