@graphty/layout 1.2.3 → 1.2.4
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/src/algorithms/index.d.ts +5 -0
- package/dist/src/algorithms/index.js +6 -0
- package/dist/src/algorithms/index.js.map +1 -0
- package/dist/src/algorithms/optimization/index.d.ts +7 -0
- package/dist/src/algorithms/optimization/index.js +7 -0
- package/dist/src/algorithms/optimization/index.js.map +1 -0
- package/dist/src/algorithms/optimization/kamada-kawai-solver.d.ts +32 -0
- package/dist/src/algorithms/optimization/kamada-kawai-solver.js +176 -0
- package/dist/src/algorithms/optimization/kamada-kawai-solver.js.map +1 -0
- package/dist/src/algorithms/optimization/lbfgs.d.ts +13 -0
- package/dist/src/algorithms/optimization/lbfgs.js +56 -0
- package/dist/src/algorithms/optimization/lbfgs.js.map +1 -0
- package/dist/src/algorithms/optimization/line-search.d.ts +15 -0
- package/dist/src/algorithms/optimization/line-search.js +37 -0
- package/dist/src/algorithms/optimization/line-search.js.map +1 -0
- package/dist/src/algorithms/optimization/types.d.ts +5 -0
- package/dist/src/algorithms/optimization/types.js +5 -0
- package/dist/src/algorithms/optimization/types.js.map +1 -0
- package/dist/src/algorithms/planarity/check.d.ts +17 -0
- package/dist/src/algorithms/planarity/check.js +30 -0
- package/dist/src/algorithms/planarity/check.js.map +1 -0
- package/dist/src/algorithms/planarity/embedding.d.ts +29 -0
- package/dist/src/algorithms/planarity/embedding.js +179 -0
- package/dist/src/algorithms/planarity/embedding.js.map +1 -0
- package/dist/src/algorithms/planarity/index.d.ts +7 -0
- package/dist/src/algorithms/planarity/index.js +8 -0
- package/dist/src/algorithms/planarity/index.js.map +1 -0
- package/dist/src/algorithms/planarity/lr-test.d.ts +15 -0
- package/dist/src/algorithms/planarity/lr-test.js +54 -0
- package/dist/src/algorithms/planarity/lr-test.js.map +1 -0
- package/dist/src/algorithms/planarity/special-graphs.d.ts +28 -0
- package/dist/src/algorithms/planarity/special-graphs.js +108 -0
- package/dist/src/algorithms/planarity/special-graphs.js.map +1 -0
- package/dist/src/generators/basic.d.ts +28 -0
- package/dist/src/generators/basic.js +79 -0
- package/dist/src/generators/basic.js.map +1 -0
- package/dist/src/generators/bipartite.d.ts +16 -0
- package/dist/src/generators/bipartite.js +40 -0
- package/dist/src/generators/bipartite.js.map +1 -0
- package/dist/src/generators/grid.d.ts +11 -0
- package/dist/src/generators/grid.js +37 -0
- package/dist/src/generators/grid.js.map +1 -0
- package/dist/src/generators/index.d.ts +8 -0
- package/dist/src/generators/index.js +9 -0
- package/dist/src/generators/index.js.map +1 -0
- package/dist/src/generators/random.d.ts +12 -0
- package/dist/src/generators/random.js +34 -0
- package/dist/src/generators/random.js.map +1 -0
- package/dist/src/generators/scale-free.d.ts +12 -0
- package/dist/src/generators/scale-free.js +62 -0
- package/dist/src/generators/scale-free.js.map +1 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.js +15 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/layouts/basic/index.d.ts +4 -0
- package/dist/src/layouts/basic/index.js +5 -0
- package/dist/src/layouts/basic/index.js.map +1 -0
- package/dist/src/layouts/basic/random.d.ts +14 -0
- package/dist/src/layouts/basic/random.js +27 -0
- package/dist/src/layouts/basic/random.js.map +1 -0
- package/dist/src/layouts/force-directed/arf.d.ts +13 -0
- package/dist/src/layouts/force-directed/arf.js +103 -0
- package/dist/src/layouts/force-directed/arf.js.map +1 -0
- package/dist/src/layouts/force-directed/forceatlas2.d.ts +22 -0
- package/dist/src/layouts/force-directed/forceatlas2.js +322 -0
- package/dist/src/layouts/force-directed/forceatlas2.js.map +1 -0
- package/dist/src/layouts/force-directed/fruchterman-reingold.d.ts +19 -0
- package/dist/src/layouts/force-directed/fruchterman-reingold.js +131 -0
- package/dist/src/layouts/force-directed/fruchterman-reingold.js.map +1 -0
- package/dist/src/layouts/force-directed/index.d.ts +8 -0
- package/dist/src/layouts/force-directed/index.js +9 -0
- package/dist/src/layouts/force-directed/index.js.map +1 -0
- package/dist/src/layouts/force-directed/kamada-kawai.d.ts +15 -0
- package/dist/src/layouts/force-directed/kamada-kawai.js +87 -0
- package/dist/src/layouts/force-directed/kamada-kawai.js.map +1 -0
- package/dist/src/layouts/force-directed/spring.d.ts +19 -0
- package/dist/src/layouts/force-directed/spring.js +23 -0
- package/dist/src/layouts/force-directed/spring.js.map +1 -0
- package/dist/src/layouts/geometric/circular.d.ts +14 -0
- package/dist/src/layouts/geometric/circular.js +67 -0
- package/dist/src/layouts/geometric/circular.js.map +1 -0
- package/dist/src/layouts/geometric/index.d.ts +6 -0
- package/dist/src/layouts/geometric/index.js +7 -0
- package/dist/src/layouts/geometric/index.js.map +1 -0
- package/dist/src/layouts/geometric/shell.d.ts +15 -0
- package/dist/src/layouts/geometric/shell.js +67 -0
- package/dist/src/layouts/geometric/shell.js.map +1 -0
- package/dist/src/layouts/geometric/spiral.d.ts +16 -0
- package/dist/src/layouts/geometric/spiral.js +73 -0
- package/dist/src/layouts/geometric/spiral.js.map +1 -0
- package/dist/src/layouts/hierarchical/bfs.d.ts +12 -0
- package/dist/src/layouts/hierarchical/bfs.js +62 -0
- package/dist/src/layouts/hierarchical/bfs.js.map +1 -0
- package/dist/src/layouts/hierarchical/bipartite.d.ts +16 -0
- package/dist/src/layouts/hierarchical/bipartite.js +72 -0
- package/dist/src/layouts/hierarchical/bipartite.js.map +1 -0
- package/dist/src/layouts/hierarchical/index.d.ts +6 -0
- package/dist/src/layouts/hierarchical/index.js +7 -0
- package/dist/src/layouts/hierarchical/index.js.map +1 -0
- package/dist/src/layouts/hierarchical/multipartite.d.ts +12 -0
- package/dist/src/layouts/hierarchical/multipartite.js +73 -0
- package/dist/src/layouts/hierarchical/multipartite.js.map +1 -0
- package/dist/src/layouts/index.d.ts +8 -0
- package/dist/src/layouts/index.js +9 -0
- package/dist/src/layouts/index.js.map +1 -0
- package/dist/src/layouts/specialized/index.d.ts +5 -0
- package/dist/src/layouts/specialized/index.js +6 -0
- package/dist/src/layouts/specialized/index.js.map +1 -0
- package/dist/src/layouts/specialized/planar.d.ts +14 -0
- package/dist/src/layouts/specialized/planar.js +47 -0
- package/dist/src/layouts/specialized/planar.js.map +1 -0
- package/dist/src/layouts/specialized/spectral.d.ts +14 -0
- package/dist/src/layouts/specialized/spectral.js +106 -0
- package/dist/src/layouts/specialized/spectral.js.map +1 -0
- package/dist/src/types/embedding.d.ts +9 -0
- package/dist/src/types/embedding.js +5 -0
- package/dist/src/types/embedding.js.map +1 -0
- package/dist/src/types/graph.d.ts +10 -0
- package/dist/src/types/graph.js +5 -0
- package/dist/src/types/graph.js.map +1 -0
- package/dist/src/types/index.d.ts +6 -0
- package/dist/src/types/index.js +7 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/types/layout.d.ts +6 -0
- package/dist/src/types/layout.js +5 -0
- package/dist/src/types/layout.js.map +1 -0
- package/dist/src/utils/graph.d.ts +34 -0
- package/dist/src/utils/graph.js +69 -0
- package/dist/src/utils/graph.js.map +1 -0
- package/dist/src/utils/index.d.ts +8 -0
- package/dist/src/utils/index.js +9 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/numpy.d.ts +17 -0
- package/dist/src/utils/numpy.js +101 -0
- package/dist/src/utils/numpy.js.map +1 -0
- package/dist/src/utils/params.d.ts +17 -0
- package/dist/src/utils/params.js +22 -0
- package/dist/src/utils/params.js.map +1 -0
- package/dist/src/utils/random.d.ts +14 -0
- package/dist/src/utils/random.js +42 -0
- package/dist/src/utils/random.js.map +1 -0
- package/dist/src/utils/rescale.d.ts +21 -0
- package/dist/src/utils/rescale.js +119 -0
- package/dist/src/utils/rescale.js.map +1 -0
- package/dist/vitest.config.js +1 -1
- package/dist/vitest.config.js.map +1 -1
- package/package.json +14 -1
- package/.env.example +0 -11
- package/.github/workflows/ci.yml +0 -101
- package/.releaserc.json +0 -22
- package/CHANGELOG.md +0 -52
- package/CLAUDE.md +0 -104
- package/CONTRIBUTING.md +0 -1
- package/DEPLOYMENT.md +0 -59
- package/build-examples-script.js +0 -26
- package/commitlint.config.js +0 -37
- package/examples/3d-force-directed.html +0 -611
- package/examples/3d-kamada-kawai.html +0 -379
- package/examples/3d-layout-comparison.html +0 -448
- package/examples/3d-spherical-layout.html +0 -319
- package/examples/arf-layout.html +0 -524
- package/examples/bfs-layout.html +0 -487
- package/examples/bipartite-layout.html +0 -382
- package/examples/circular-layout.html +0 -292
- package/examples/forceatlas2-layout.html +0 -588
- package/examples/index.html +0 -241
- package/examples/kamada-kawai-layout.html +0 -425
- package/examples/layout-helpers.js +0 -23
- package/examples/layout.js +0 -2304
- package/examples/multipartite-layout.html +0 -410
- package/examples/planar-layout.html +0 -388
- package/examples/random-layout.html +0 -328
- package/examples/shell-layout.html +0 -323
- package/examples/spectral-layout.html +0 -335
- package/examples/spiral-layout.html +0 -447
- package/examples/spring-layout.html +0 -313
- package/test/arf-layout.test.ts +0 -443
- package/test/bfs-layout.test.ts +0 -427
- package/test/bipartite-layout.test.ts +0 -344
- package/test/circular-layout.test.ts +0 -442
- package/test/forceatlas2-layout.test.ts +0 -405
- package/test/fruchterman-reingold-layout.test.ts +0 -477
- package/test/graph-generators.test.ts +0 -450
- package/test/kamada-kawai-layout.test.ts +0 -623
- package/test/multipartite-layout.test.ts +0 -404
- package/test/planar-layout.test.ts +0 -266
- package/test/random-layout.test.ts +0 -254
- package/test/rescale-layout.test.ts +0 -373
- package/test/shell-layout.test.ts +0 -347
- package/test/spectral-layout.test.ts +0 -378
- package/test/spiral-layout.test.ts +0 -338
- package/test/spring-layout.test.ts +0 -241
- package/test/test-utils.ts +0 -34
- package/test/utils-graph.test.ts +0 -155
- package/test/utils-index.test.ts +0 -77
- package/test/utils-numpy.test.ts +0 -272
- package/test/utils-params.test.ts +0 -99
- package/test/utils-random.test.ts +0 -229
- package/tsconfig.json +0 -16
- package/vite.config.js +0 -36
- package/vitest.config.ts +0 -30
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { getNodesFromGraph } from '../../utils/graph';
|
|
2
|
+
import { _processParams } from '../../utils/params';
|
|
3
|
+
import { rescaleLayout } from '../../utils/rescale';
|
|
4
|
+
import { RandomNumberGenerator } from '../../utils/random';
|
|
5
|
+
/**
|
|
6
|
+
* Position nodes using the ForceAtlas2 force-directed algorithm.
|
|
7
|
+
*
|
|
8
|
+
* @param G - Graph
|
|
9
|
+
* @param pos - Initial positions for nodes
|
|
10
|
+
* @param maxIter - Maximum number of iterations
|
|
11
|
+
* @param jitterTolerance - Controls tolerance for node speed adjustments
|
|
12
|
+
* @param scalingRatio - Scaling of attraction and repulsion forces
|
|
13
|
+
* @param gravity - Attraction to center to prevent disconnected components from drifting
|
|
14
|
+
* @param distributedAction - Distributes attraction force among nodes
|
|
15
|
+
* @param strongGravity - Uses a stronger gravity model
|
|
16
|
+
* @param nodeMass - Dictionary mapping nodes to their masses
|
|
17
|
+
* @param nodeSize - Dictionary mapping nodes to their sizes
|
|
18
|
+
* @param weight - Edge attribute for weight
|
|
19
|
+
* @param dissuadeHubs - Whether to prevent hub nodes from clustering
|
|
20
|
+
* @param linlog - Whether to use logarithmic attraction
|
|
21
|
+
* @param seed - Random seed for initial positions
|
|
22
|
+
* @param dim - Dimension of layout
|
|
23
|
+
* @returns Positions dictionary keyed by node
|
|
24
|
+
*/
|
|
25
|
+
export function forceatlas2Layout(G, pos = null, maxIter = 100, jitterTolerance = 1.0, scalingRatio = 2.0, gravity = 1.0, distributedAction = false, strongGravity = false, nodeMass = null, nodeSize = null, weight = null, dissuadeHubs = false, linlog = false, seed = null, dim = 2) {
|
|
26
|
+
const processed = _processParams(G, null, dim);
|
|
27
|
+
const graph = processed.G;
|
|
28
|
+
const nodes = getNodesFromGraph(graph);
|
|
29
|
+
if (nodes.length === 0) {
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
// Initialize random number generator
|
|
33
|
+
const rng = new RandomNumberGenerator(seed ?? undefined);
|
|
34
|
+
// Initialize positions if not provided
|
|
35
|
+
let posArray;
|
|
36
|
+
if (pos === null) {
|
|
37
|
+
pos = {};
|
|
38
|
+
posArray = new Array(nodes.length);
|
|
39
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
40
|
+
posArray[i] = Array(dim).fill(0).map(() => rng.rand() * 2 - 1);
|
|
41
|
+
pos[nodes[i]] = posArray[i];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else if (Object.keys(pos).length === nodes.length) {
|
|
45
|
+
// Use provided positions
|
|
46
|
+
posArray = new Array(nodes.length);
|
|
47
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
48
|
+
posArray[i] = [...pos[nodes[i]]];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// Some nodes don't have positions, initialize within the range of existing positions
|
|
53
|
+
let minPos = Array(dim).fill(Number.POSITIVE_INFINITY);
|
|
54
|
+
let maxPos = Array(dim).fill(Number.NEGATIVE_INFINITY);
|
|
55
|
+
// Find min and max of existing positions
|
|
56
|
+
for (const node in pos) {
|
|
57
|
+
for (let d = 0; d < dim; d++) {
|
|
58
|
+
minPos[d] = Math.min(minPos[d], pos[node][d]);
|
|
59
|
+
maxPos[d] = Math.max(maxPos[d], pos[node][d]);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
posArray = new Array(nodes.length);
|
|
63
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
64
|
+
const node = nodes[i];
|
|
65
|
+
if (pos[node]) {
|
|
66
|
+
posArray[i] = [...pos[node]];
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
posArray[i] = Array(dim).fill(0).map((_, d) => minPos[d] + rng.rand() * (maxPos[d] - minPos[d]));
|
|
70
|
+
pos[node] = posArray[i];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Initialize mass and size arrays
|
|
75
|
+
const mass = new Array(nodes.length).fill(0);
|
|
76
|
+
const size = new Array(nodes.length).fill(0);
|
|
77
|
+
// Flag to track whether to adjust for node sizes
|
|
78
|
+
const adjustSizes = nodeSize !== null;
|
|
79
|
+
// Set node masses and sizes
|
|
80
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
81
|
+
const node = nodes[i];
|
|
82
|
+
mass[i] = nodeMass && nodeMass[node] ?
|
|
83
|
+
nodeMass[node] :
|
|
84
|
+
(Array.isArray(graph) ? 1 : getNodeDegree(graph, node) + 1);
|
|
85
|
+
size[i] = nodeSize && nodeSize[node] ? nodeSize[node] : 1;
|
|
86
|
+
}
|
|
87
|
+
// Create adjacency matrix
|
|
88
|
+
const n = nodes.length;
|
|
89
|
+
const A = Array(n).fill(0).map(() => Array(n).fill(0));
|
|
90
|
+
// Populate adjacency matrix with edge weights
|
|
91
|
+
const edges = Array.isArray(graph) ? [] : graph.edges();
|
|
92
|
+
const nodeIndices = {};
|
|
93
|
+
nodes.forEach((node, i) => { nodeIndices[node] = i; });
|
|
94
|
+
for (const [source, target] of edges) {
|
|
95
|
+
const i = nodeIndices[source];
|
|
96
|
+
const j = nodeIndices[target];
|
|
97
|
+
// Use edge weight if provided, otherwise default to 1
|
|
98
|
+
let edgeWeight = 1;
|
|
99
|
+
if (weight && !Array.isArray(graph) && graph.getEdgeData) {
|
|
100
|
+
edgeWeight = graph.getEdgeData(source, target, weight) || 1;
|
|
101
|
+
}
|
|
102
|
+
A[i][j] = edgeWeight;
|
|
103
|
+
A[j][i] = edgeWeight; // For undirected graphs
|
|
104
|
+
}
|
|
105
|
+
// Initialize force arrays
|
|
106
|
+
const gravities = Array(n).fill(0).map(() => Array(dim).fill(0));
|
|
107
|
+
const attraction = Array(n).fill(0).map(() => Array(dim).fill(0));
|
|
108
|
+
const repulsion = Array(n).fill(0).map(() => Array(dim).fill(0));
|
|
109
|
+
// Simulation parameters
|
|
110
|
+
let speed = 1;
|
|
111
|
+
let speedEfficiency = 1;
|
|
112
|
+
let swing = 1;
|
|
113
|
+
let traction = 1;
|
|
114
|
+
// Helper function to estimate factor for force scaling
|
|
115
|
+
function estimateFactor(n, swing, traction, speed, speedEfficiency, jitterTolerance) {
|
|
116
|
+
// Optimal jitter parameters
|
|
117
|
+
const optJitter = 0.05 * Math.sqrt(n);
|
|
118
|
+
const minJitter = Math.sqrt(optJitter);
|
|
119
|
+
const maxJitter = 10;
|
|
120
|
+
const minSpeedEfficiency = 0.05;
|
|
121
|
+
// Estimate jitter based on current state
|
|
122
|
+
const other = Math.min(maxJitter, optJitter * traction / (n * n));
|
|
123
|
+
let jitter = jitterTolerance * Math.max(minJitter, other);
|
|
124
|
+
// Adjust speed efficiency based on swing/traction ratio
|
|
125
|
+
if (swing / traction > 2.0) {
|
|
126
|
+
if (speedEfficiency > minSpeedEfficiency) {
|
|
127
|
+
speedEfficiency *= 0.5;
|
|
128
|
+
}
|
|
129
|
+
jitter = Math.max(jitter, jitterTolerance);
|
|
130
|
+
}
|
|
131
|
+
// Calculate target speed
|
|
132
|
+
let targetSpeed = swing === 0 ?
|
|
133
|
+
Number.POSITIVE_INFINITY :
|
|
134
|
+
jitter * speedEfficiency * traction / swing;
|
|
135
|
+
// Further adjust speed efficiency
|
|
136
|
+
if (swing > jitter * traction) {
|
|
137
|
+
if (speedEfficiency > minSpeedEfficiency) {
|
|
138
|
+
speedEfficiency *= 0.7;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else if (speed < 1000) {
|
|
142
|
+
speedEfficiency *= 1.3;
|
|
143
|
+
}
|
|
144
|
+
// Limit the speed increase
|
|
145
|
+
const maxRise = 0.5;
|
|
146
|
+
speed = speed + Math.min(targetSpeed - speed, maxRise * speed);
|
|
147
|
+
return [speed, speedEfficiency];
|
|
148
|
+
}
|
|
149
|
+
// Main simulation loop
|
|
150
|
+
for (let iter = 0; iter < maxIter; iter++) {
|
|
151
|
+
// Reset forces for this iteration
|
|
152
|
+
for (let i = 0; i < n; i++) {
|
|
153
|
+
for (let d = 0; d < dim; d++) {
|
|
154
|
+
attraction[i][d] = 0;
|
|
155
|
+
repulsion[i][d] = 0;
|
|
156
|
+
gravities[i][d] = 0;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Compute pairwise differences and distances
|
|
160
|
+
const diff = Array(n).fill(0).map(() => Array(n).fill(0).map(() => Array(dim).fill(0)));
|
|
161
|
+
const distance = Array(n).fill(0).map(() => Array(n).fill(0));
|
|
162
|
+
for (let i = 0; i < n; i++) {
|
|
163
|
+
for (let j = 0; j < n; j++) {
|
|
164
|
+
if (i === j)
|
|
165
|
+
continue;
|
|
166
|
+
for (let d = 0; d < dim; d++) {
|
|
167
|
+
diff[i][j][d] = posArray[i][d] - posArray[j][d];
|
|
168
|
+
}
|
|
169
|
+
distance[i][j] = Math.sqrt(diff[i][j].reduce((sum, d) => sum + d * d, 0));
|
|
170
|
+
// Prevent division by zero
|
|
171
|
+
if (distance[i][j] < 0.01)
|
|
172
|
+
distance[i][j] = 0.01;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Calculate attraction forces
|
|
176
|
+
if (linlog) {
|
|
177
|
+
// Logarithmic attraction model
|
|
178
|
+
for (let i = 0; i < n; i++) {
|
|
179
|
+
for (let j = 0; j < n; j++) {
|
|
180
|
+
if (i === j || A[i][j] === 0)
|
|
181
|
+
continue;
|
|
182
|
+
const dist = distance[i][j];
|
|
183
|
+
const factor = -Math.log(1 + dist) / dist * A[i][j];
|
|
184
|
+
for (let d = 0; d < dim; d++) {
|
|
185
|
+
const force = factor * diff[i][j][d];
|
|
186
|
+
attraction[i][d] += force;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
// Linear attraction model
|
|
193
|
+
for (let i = 0; i < n; i++) {
|
|
194
|
+
for (let j = 0; j < n; j++) {
|
|
195
|
+
if (i === j || A[i][j] === 0)
|
|
196
|
+
continue;
|
|
197
|
+
for (let d = 0; d < dim; d++) {
|
|
198
|
+
const force = -diff[i][j][d] * A[i][j];
|
|
199
|
+
attraction[i][d] += force;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Apply distributed attraction if enabled
|
|
205
|
+
if (distributedAction) {
|
|
206
|
+
for (let i = 0; i < n; i++) {
|
|
207
|
+
for (let d = 0; d < dim; d++) {
|
|
208
|
+
attraction[i][d] /= mass[i];
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// Calculate repulsion forces
|
|
213
|
+
for (let i = 0; i < n; i++) {
|
|
214
|
+
for (let j = 0; j < n; j++) {
|
|
215
|
+
if (i === j)
|
|
216
|
+
continue;
|
|
217
|
+
let dist = distance[i][j];
|
|
218
|
+
// Adjust distance for node sizes if needed
|
|
219
|
+
if (adjustSizes) {
|
|
220
|
+
dist -= size[i] - size[j];
|
|
221
|
+
dist = Math.max(dist, 0.01); // Prevent negative or zero distances
|
|
222
|
+
}
|
|
223
|
+
const distSquared = dist * dist;
|
|
224
|
+
const massProduct = mass[i] * mass[j];
|
|
225
|
+
const factor = (massProduct / distSquared) * scalingRatio;
|
|
226
|
+
for (let d = 0; d < dim; d++) {
|
|
227
|
+
const direction = diff[i][j][d] / dist;
|
|
228
|
+
repulsion[i][d] += direction * factor;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// Calculate gravity forces
|
|
233
|
+
// First find the center of mass
|
|
234
|
+
const centerOfMass = Array(dim).fill(0);
|
|
235
|
+
for (let i = 0; i < n; i++) {
|
|
236
|
+
for (let d = 0; d < dim; d++) {
|
|
237
|
+
centerOfMass[d] += posArray[i][d] / n;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
for (let i = 0; i < n; i++) {
|
|
241
|
+
const posCentered = Array(dim);
|
|
242
|
+
for (let d = 0; d < dim; d++) {
|
|
243
|
+
posCentered[d] = posArray[i][d] - centerOfMass[d];
|
|
244
|
+
}
|
|
245
|
+
if (strongGravity) {
|
|
246
|
+
// Strong gravity model
|
|
247
|
+
for (let d = 0; d < dim; d++) {
|
|
248
|
+
gravities[i][d] = -gravity * mass[i] * posCentered[d];
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
// Regular gravity model
|
|
253
|
+
const dist = Math.sqrt(posCentered.reduce((sum, val) => sum + val * val, 0));
|
|
254
|
+
if (dist > 0.01) {
|
|
255
|
+
for (let d = 0; d < dim; d++) {
|
|
256
|
+
const direction = posCentered[d] / dist;
|
|
257
|
+
gravities[i][d] = -gravity * mass[i] * direction;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// Calculate total forces and update positions
|
|
263
|
+
const update = Array(n).fill(0).map(() => Array(dim).fill(0));
|
|
264
|
+
let totalSwing = 0;
|
|
265
|
+
let totalTraction = 0;
|
|
266
|
+
for (let i = 0; i < n; i++) {
|
|
267
|
+
for (let d = 0; d < dim; d++) {
|
|
268
|
+
update[i][d] = attraction[i][d] + repulsion[i][d] + gravities[i][d];
|
|
269
|
+
}
|
|
270
|
+
// Calculate swing and traction for this node
|
|
271
|
+
const oldPos = [...posArray[i]];
|
|
272
|
+
const newPos = oldPos.map((p, d) => p + update[i][d]);
|
|
273
|
+
const swingVector = oldPos.map((p, d) => p - newPos[d]);
|
|
274
|
+
const tractionVector = oldPos.map((p, d) => p + newPos[d]);
|
|
275
|
+
const swingMagnitude = Math.sqrt(swingVector.reduce((sum, val) => sum + val * val, 0));
|
|
276
|
+
const tractionMagnitude = Math.sqrt(tractionVector.reduce((sum, val) => sum + val * val, 0));
|
|
277
|
+
totalSwing += mass[i] * swingMagnitude;
|
|
278
|
+
totalTraction += 0.5 * mass[i] * tractionMagnitude;
|
|
279
|
+
}
|
|
280
|
+
// Update speed and efficiency
|
|
281
|
+
[speed, speedEfficiency] = estimateFactor(n, totalSwing, totalTraction, speed, speedEfficiency, jitterTolerance);
|
|
282
|
+
// Apply forces to update positions
|
|
283
|
+
let totalMovement = 0;
|
|
284
|
+
for (let i = 0; i < n; i++) {
|
|
285
|
+
let factor;
|
|
286
|
+
if (adjustSizes) {
|
|
287
|
+
// Calculate displacement magnitude
|
|
288
|
+
const df = Math.sqrt(update[i].reduce((sum, val) => sum + val * val, 0));
|
|
289
|
+
const swinging = mass[i] * df;
|
|
290
|
+
// Determine scaling factor with size adjustments
|
|
291
|
+
factor = 0.1 * speed / (1 + Math.sqrt(speed * swinging));
|
|
292
|
+
factor = Math.min(factor * df, 10) / df;
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
// Standard scaling factor
|
|
296
|
+
const swinging = mass[i] * Math.sqrt(update[i].reduce((sum, val) => sum + val * val, 0));
|
|
297
|
+
factor = speed / (1 + Math.sqrt(speed * swinging));
|
|
298
|
+
}
|
|
299
|
+
// Apply factor to update position
|
|
300
|
+
for (let d = 0; d < dim; d++) {
|
|
301
|
+
const movement = update[i][d] * factor;
|
|
302
|
+
posArray[i][d] += movement;
|
|
303
|
+
totalMovement += Math.abs(movement);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
// Check for convergence
|
|
307
|
+
if (totalMovement < 1e-10) {
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
// Create position dictionary
|
|
312
|
+
const positions = {};
|
|
313
|
+
for (let i = 0; i < n; i++) {
|
|
314
|
+
positions[nodes[i]] = posArray[i];
|
|
315
|
+
}
|
|
316
|
+
return rescaleLayout(positions);
|
|
317
|
+
}
|
|
318
|
+
// Helper function to get node degree
|
|
319
|
+
function getNodeDegree(graph, node) {
|
|
320
|
+
return graph.edges().filter((edge) => edge[0] === node || edge[1] === node).length;
|
|
321
|
+
}
|
|
322
|
+
//# sourceMappingURL=forceatlas2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forceatlas2.js","sourceRoot":"","sources":["../../../../src/layouts/force-directed/forceatlas2.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fruchterman-Reingold force-directed layout algorithm
|
|
3
|
+
*/
|
|
4
|
+
import { Graph, Node, PositionMap } from '../../types';
|
|
5
|
+
/**
|
|
6
|
+
* Position nodes using Fruchterman-Reingold force-directed algorithm.
|
|
7
|
+
*
|
|
8
|
+
* @param {Object} G - Graph or list of nodes
|
|
9
|
+
* @param {number} k - Optimal distance between nodes
|
|
10
|
+
* @param {Object} pos - Initial positions for nodes
|
|
11
|
+
* @param {Array} fixed - Nodes to keep fixed at initial position
|
|
12
|
+
* @param {number} iterations - Maximum number of iterations
|
|
13
|
+
* @param {number} scale - Scale factor for positions
|
|
14
|
+
* @param {Array|null} center - Coordinate pair around which to center the layout
|
|
15
|
+
* @param {number} dim - Dimension of layout
|
|
16
|
+
* @param {number} seed - Random seed for initial positions
|
|
17
|
+
* @returns {Object} Positions dictionary keyed by node
|
|
18
|
+
*/
|
|
19
|
+
export declare function fruchtermanReingoldLayout(G: Graph, k?: number | null, pos?: PositionMap | null, fixed?: Node[] | null, iterations?: number, scale?: number, center?: number[] | null, dim?: number, seed?: number | null): PositionMap;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fruchterman-Reingold force-directed layout algorithm
|
|
3
|
+
*/
|
|
4
|
+
import { _processParams } from '../../utils/params';
|
|
5
|
+
import { getNodesFromGraph, getEdgesFromGraph } from '../../utils/graph';
|
|
6
|
+
import { RandomNumberGenerator } from '../../utils/random';
|
|
7
|
+
import { rescaleLayout } from '../../utils/rescale';
|
|
8
|
+
/**
|
|
9
|
+
* Position nodes using Fruchterman-Reingold force-directed algorithm.
|
|
10
|
+
*
|
|
11
|
+
* @param {Object} G - Graph or list of nodes
|
|
12
|
+
* @param {number} k - Optimal distance between nodes
|
|
13
|
+
* @param {Object} pos - Initial positions for nodes
|
|
14
|
+
* @param {Array} fixed - Nodes to keep fixed at initial position
|
|
15
|
+
* @param {number} iterations - Maximum number of iterations
|
|
16
|
+
* @param {number} scale - Scale factor for positions
|
|
17
|
+
* @param {Array|null} center - Coordinate pair around which to center the layout
|
|
18
|
+
* @param {number} dim - Dimension of layout
|
|
19
|
+
* @param {number} seed - Random seed for initial positions
|
|
20
|
+
* @returns {Object} Positions dictionary keyed by node
|
|
21
|
+
*/
|
|
22
|
+
export function fruchtermanReingoldLayout(G, k = null, pos = null, fixed = null, iterations = 50, scale = 1, center = null, dim = 2, seed = null) {
|
|
23
|
+
const processed = _processParams(G, center, dim);
|
|
24
|
+
let graph = processed.G;
|
|
25
|
+
center = processed.center;
|
|
26
|
+
const nodes = getNodesFromGraph(graph);
|
|
27
|
+
const edges = getEdgesFromGraph(graph);
|
|
28
|
+
if (nodes.length === 0) {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
if (nodes.length === 1) {
|
|
32
|
+
const singlePos = {};
|
|
33
|
+
singlePos[nodes[0]] = center;
|
|
34
|
+
return singlePos;
|
|
35
|
+
}
|
|
36
|
+
// Set up initial positions
|
|
37
|
+
let positions = {};
|
|
38
|
+
if (pos) {
|
|
39
|
+
// Use provided positions
|
|
40
|
+
for (const node of nodes) {
|
|
41
|
+
if (pos[node]) {
|
|
42
|
+
positions[node] = [...pos[node]];
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
const rng = new RandomNumberGenerator(seed ?? undefined);
|
|
46
|
+
positions[node] = rng.rand(dim);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// Random initial positions
|
|
52
|
+
const rng = new RandomNumberGenerator(seed ?? undefined);
|
|
53
|
+
for (const node of nodes) {
|
|
54
|
+
positions[node] = rng.rand(dim);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Set up fixed nodes
|
|
58
|
+
const fixedNodes = new Set(fixed || []);
|
|
59
|
+
// Optimal distance between nodes
|
|
60
|
+
if (!k) {
|
|
61
|
+
k = 1.0 / Math.sqrt(nodes.length);
|
|
62
|
+
}
|
|
63
|
+
// Initialize temperature
|
|
64
|
+
let t = 0.1;
|
|
65
|
+
// Calculate temperature reduction
|
|
66
|
+
const dt = t / (iterations + 1);
|
|
67
|
+
// Simple cooling schedule
|
|
68
|
+
for (let i = 0; i < iterations; i++) {
|
|
69
|
+
// Calculate repulsive forces
|
|
70
|
+
const displacement = {};
|
|
71
|
+
for (const node of nodes) {
|
|
72
|
+
displacement[node] = Array(dim).fill(0);
|
|
73
|
+
}
|
|
74
|
+
// Repulsive forces between nodes
|
|
75
|
+
for (let v1i = 0; v1i < nodes.length; v1i++) {
|
|
76
|
+
const v1 = nodes[v1i];
|
|
77
|
+
for (let v2i = v1i + 1; v2i < nodes.length; v2i++) {
|
|
78
|
+
const v2 = nodes[v2i];
|
|
79
|
+
// Difference vector
|
|
80
|
+
const delta = positions[v1].map((p, i) => p - positions[v2][i]);
|
|
81
|
+
// Distance
|
|
82
|
+
const distance = Math.sqrt(delta.reduce((sum, d) => sum + d * d, 0)) || 0.1;
|
|
83
|
+
// Force
|
|
84
|
+
const force = (k * k) / distance;
|
|
85
|
+
// Add force to displacement
|
|
86
|
+
for (let j = 0; j < dim; j++) {
|
|
87
|
+
const direction = delta[j] / distance;
|
|
88
|
+
displacement[v1][j] += direction * force;
|
|
89
|
+
displacement[v2][j] -= direction * force;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Attractive forces between connected nodes
|
|
94
|
+
for (const [source, target] of edges) {
|
|
95
|
+
// Difference vector
|
|
96
|
+
const delta = positions[source].map((p, i) => p - positions[target][i]);
|
|
97
|
+
// Distance
|
|
98
|
+
const distance = Math.sqrt(delta.reduce((sum, d) => sum + d * d, 0)) || 0.1;
|
|
99
|
+
// Force
|
|
100
|
+
const force = (distance * distance) / k;
|
|
101
|
+
// Add force to displacement
|
|
102
|
+
for (let j = 0; j < dim; j++) {
|
|
103
|
+
const direction = delta[j] / distance;
|
|
104
|
+
displacement[source][j] -= direction * force;
|
|
105
|
+
displacement[target][j] += direction * force;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Update positions
|
|
109
|
+
for (const node of nodes) {
|
|
110
|
+
if (fixedNodes.has(node))
|
|
111
|
+
continue;
|
|
112
|
+
// Calculate displacement magnitude
|
|
113
|
+
const magnitude = Math.sqrt(displacement[node].reduce((sum, d) => sum + d * d, 0));
|
|
114
|
+
// Limit maximum displacement by temperature
|
|
115
|
+
const limitedMagnitude = Math.min(magnitude, t);
|
|
116
|
+
// Update position
|
|
117
|
+
for (let j = 0; j < dim; j++) {
|
|
118
|
+
const direction = magnitude === 0 ? 0 : displacement[node][j] / magnitude;
|
|
119
|
+
positions[node][j] += direction * limitedMagnitude;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Cool temperature
|
|
123
|
+
t -= dt;
|
|
124
|
+
}
|
|
125
|
+
// Rescale positions
|
|
126
|
+
if (!fixed) {
|
|
127
|
+
positions = rescaleLayout(positions, scale, center);
|
|
128
|
+
}
|
|
129
|
+
return positions;
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=fruchterman-reingold.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fruchterman-reingold.js","sourceRoot":"","sources":["../../../../src/layouts/force-directed/fruchterman-reingold.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Force-directed layout algorithms
|
|
3
|
+
*/
|
|
4
|
+
export { springLayout } from './spring';
|
|
5
|
+
export { fruchtermanReingoldLayout } from './fruchterman-reingold';
|
|
6
|
+
export { kamadaKawaiLayout } from './kamada-kawai';
|
|
7
|
+
export { forceatlas2Layout } from './forceatlas2';
|
|
8
|
+
export { arfLayout } from './arf';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Force-directed layout algorithms
|
|
3
|
+
*/
|
|
4
|
+
export { springLayout } from './spring';
|
|
5
|
+
export { fruchtermanReingoldLayout } from './fruchterman-reingold';
|
|
6
|
+
export { kamadaKawaiLayout } from './kamada-kawai';
|
|
7
|
+
export { forceatlas2Layout } from './forceatlas2';
|
|
8
|
+
export { arfLayout } from './arf';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/layouts/force-directed/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Graph, PositionMap } from '../../types';
|
|
2
|
+
import type { DistanceMap } from '../../algorithms/optimization';
|
|
3
|
+
/**
|
|
4
|
+
* Position nodes using Kamada-Kawai path-length cost-function.
|
|
5
|
+
*
|
|
6
|
+
* @param G - NetworkX graph or list of nodes
|
|
7
|
+
* @param dist - A two-level dictionary of optimal distances between nodes
|
|
8
|
+
* @param pos - Initial positions for nodes
|
|
9
|
+
* @param weight - The edge attribute used for edge weights
|
|
10
|
+
* @param scale - Scale factor for positions
|
|
11
|
+
* @param center - Coordinate pair around which to center the layout
|
|
12
|
+
* @param dim - Dimension of layout
|
|
13
|
+
* @returns Positions dictionary keyed by node
|
|
14
|
+
*/
|
|
15
|
+
export declare function kamadaKawaiLayout(G: Graph, dist?: DistanceMap | null, pos?: PositionMap | null, weight?: string, scale?: number, center?: number[] | null, dim?: number): PositionMap;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { getNodesFromGraph } from '../../utils/graph';
|
|
2
|
+
import { _processParams } from '../../utils/params';
|
|
3
|
+
import { rescaleLayout } from '../../utils/rescale';
|
|
4
|
+
import { circularLayout } from '../geometric/circular';
|
|
5
|
+
import { _computeShortestPathDistances, _kamadaKawaiSolve } from '../../algorithms/optimization';
|
|
6
|
+
/**
|
|
7
|
+
* Position nodes using Kamada-Kawai path-length cost-function.
|
|
8
|
+
*
|
|
9
|
+
* @param G - NetworkX graph or list of nodes
|
|
10
|
+
* @param dist - A two-level dictionary of optimal distances between nodes
|
|
11
|
+
* @param pos - Initial positions for nodes
|
|
12
|
+
* @param weight - The edge attribute used for edge weights
|
|
13
|
+
* @param scale - Scale factor for positions
|
|
14
|
+
* @param center - Coordinate pair around which to center the layout
|
|
15
|
+
* @param dim - Dimension of layout
|
|
16
|
+
* @returns Positions dictionary keyed by node
|
|
17
|
+
*/
|
|
18
|
+
export function kamadaKawaiLayout(G, dist = null, pos = null, weight = 'weight', scale = 1, center = null, dim = 2) {
|
|
19
|
+
const processed = _processParams(G, center, dim);
|
|
20
|
+
const graph = processed.G;
|
|
21
|
+
center = processed.center;
|
|
22
|
+
const nodes = getNodesFromGraph(graph);
|
|
23
|
+
if (nodes.length === 0) {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
if (nodes.length === 1) {
|
|
27
|
+
return { [nodes[0]]: center };
|
|
28
|
+
}
|
|
29
|
+
// Initialize distance matrix
|
|
30
|
+
if (!dist) {
|
|
31
|
+
// Kamada-Kawai requires a proper Graph, not just a list of nodes
|
|
32
|
+
if (Array.isArray(graph)) {
|
|
33
|
+
throw new Error('Kamada-Kawai layout requires a Graph with edges, not just a list of nodes');
|
|
34
|
+
}
|
|
35
|
+
dist = _computeShortestPathDistances(graph, weight);
|
|
36
|
+
}
|
|
37
|
+
// Convert distances to a matrix
|
|
38
|
+
const nodesArray = Array.from(nodes);
|
|
39
|
+
const nNodes = nodesArray.length;
|
|
40
|
+
const distMatrix = Array(nNodes).fill(0).map(() => Array(nNodes).fill(1e6));
|
|
41
|
+
for (let i = 0; i < nNodes; i++) {
|
|
42
|
+
const nodeI = nodesArray[i];
|
|
43
|
+
distMatrix[i][i] = 0;
|
|
44
|
+
if (!dist[nodeI])
|
|
45
|
+
continue;
|
|
46
|
+
for (let j = 0; j < nNodes; j++) {
|
|
47
|
+
const nodeJ = nodesArray[j];
|
|
48
|
+
if (dist[nodeI][nodeJ] !== undefined) {
|
|
49
|
+
distMatrix[i][j] = dist[nodeI][nodeJ];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Initialize positions if not provided
|
|
54
|
+
if (!pos) {
|
|
55
|
+
if (dim >= 2) {
|
|
56
|
+
// Use circular/spherical layout for 2D and 3D
|
|
57
|
+
pos = circularLayout(G, 1, center, dim);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
// For 1D, use a linear layout
|
|
61
|
+
const posArray = {};
|
|
62
|
+
nodesArray.forEach((node, i) => {
|
|
63
|
+
posArray[node] = [i / (nNodes - 1 || 1)];
|
|
64
|
+
});
|
|
65
|
+
pos = posArray;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Convert positions to array for computation
|
|
69
|
+
const posArray = new Array(nNodes);
|
|
70
|
+
for (let i = 0; i < nNodes; i++) {
|
|
71
|
+
const node = nodesArray[i];
|
|
72
|
+
posArray[i] = pos[node] ? [...pos[node]] : Array(dim).fill(0);
|
|
73
|
+
// Ensure correct dimensionality
|
|
74
|
+
while (posArray[i].length < dim) {
|
|
75
|
+
posArray[i].push(0);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Run the Kamada-Kawai algorithm
|
|
79
|
+
const newPositions = _kamadaKawaiSolve(distMatrix, posArray, dim);
|
|
80
|
+
// Convert positions array back to dictionary and rescale
|
|
81
|
+
const finalPos = {};
|
|
82
|
+
for (let i = 0; i < nNodes; i++) {
|
|
83
|
+
finalPos[nodesArray[i]] = newPositions[i];
|
|
84
|
+
}
|
|
85
|
+
return rescaleLayout(finalPos, scale, center);
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=kamada-kawai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kamada-kawai.js","sourceRoot":"","sources":["../../../../src/layouts/force-directed/kamada-kawai.ts"],"names":[],"mappings":"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"}
|