@neo4j-nvl/layout-workers 1.2.0-d88ba7c2 → 1.2.0-dbc13ec2
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/lib/__mocks__/index.d.ts +10 -9
- package/lib/__mocks__/index.js +2 -2
- package/lib/hierarchical-layout/HierarchicalLayout.fallback.js +2 -2
- package/lib/hierarchical-layout/HierarchicalLayout.worker.js +2 -2
- package/lib/hierarchical-layout/dagre-layout-impl.d.ts +1 -1
- package/lib/hierarchical-layout/dagre-layout-impl.js +38 -9
- package/lib/hierarchical-layout/dagre-layout-impl.test.js +90 -0
- package/lib/index.d.ts +1 -3
- package/lib/index.js +1 -3
- package/package.json +3 -4
- package/lib/cosebilkent-layout/CoseBilkentLayout.fallback.d.ts +0 -10
- package/lib/cosebilkent-layout/CoseBilkentLayout.fallback.js +0 -16
- package/lib/cosebilkent-layout/CoseBilkentLayout.worker.d.ts +0 -1
- package/lib/cosebilkent-layout/CoseBilkentLayout.worker.js +0 -9
- package/lib/cosebilkent-layout/cose-bilkent-layout-impl.d.ts +0 -3
- package/lib/cosebilkent-layout/cose-bilkent-layout-impl.js +0 -29
- package/lib/cosebilkent-layout/workerFactory.d.mts +0 -1
- package/lib/cosebilkent-layout/workerFactory.mjs +0 -8
package/lib/__mocks__/index.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
port
|
|
3
|
-
start: jest.Mock<any, any, any>;
|
|
4
|
-
onmessage: jest.Mock<any, any, any>;
|
|
5
|
-
postMessage: jest.Mock<any, any, any>;
|
|
6
|
-
close: jest.Mock<any, any, any>;
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
export function createHierarchicalLayoutWorker(): {
|
|
1
|
+
declare namespace sharedWorkerMock {
|
|
2
|
+
namespace port {
|
|
3
|
+
let start: jest.Mock<any, any, any>;
|
|
4
|
+
let onmessage: jest.Mock<any, any, any>;
|
|
5
|
+
let postMessage: jest.Mock<any, any, any>;
|
|
6
|
+
let close: jest.Mock<any, any, any>;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export declare function createHierarchicalLayoutWorker(): {
|
|
10
10
|
port: {
|
|
11
11
|
start: jest.Mock<any, any, any>;
|
|
12
12
|
onmessage: jest.Mock<any, any, any>;
|
|
@@ -14,3 +14,4 @@ export function createHierarchicalLayoutWorker(): {
|
|
|
14
14
|
close: jest.Mock<any, any, any>;
|
|
15
15
|
};
|
|
16
16
|
};
|
|
17
|
+
export { sharedWorkerMock as hierarchicalLayoutFallbackWorker };
|
package/lib/__mocks__/index.js
CHANGED
|
@@ -7,6 +7,6 @@ const sharedWorkerMock = {
|
|
|
7
7
|
}
|
|
8
8
|
};
|
|
9
9
|
module.exports = {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
createHierarchicalLayoutWorker: () => sharedWorkerMock,
|
|
11
|
+
hierarchicalLayoutFallbackWorker: sharedWorkerMock
|
|
12
12
|
};
|
|
@@ -4,8 +4,8 @@ import { layout } from './dagre-layout-impl.js';
|
|
|
4
4
|
class HierarchicalLayoutFallbackWorker {
|
|
5
5
|
start() { }
|
|
6
6
|
postMessage(data) {
|
|
7
|
-
const { nodes, nodeIds, idToPosition, rels, direction, packing, pixelRatio, forcedDelay = 0 } = data;
|
|
8
|
-
const layoutData = layout(nodes, nodeIds, idToPosition, rels, direction, packing, pixelRatio);
|
|
7
|
+
const { nodes, nodeIds, idToPosition, rels, direction, packing, pixelRatio, forcedDelay = 0, clusterAssignments } = data;
|
|
8
|
+
const layoutData = layout(nodes, nodeIds, idToPosition, rels, direction, packing, pixelRatio, clusterAssignments);
|
|
9
9
|
if (forcedDelay) {
|
|
10
10
|
setTimeout(() => {
|
|
11
11
|
this.onmessage({ data: layoutData });
|
|
@@ -2,8 +2,8 @@ import { layout } from './dagre-layout-impl.js';
|
|
|
2
2
|
onconnect = ({ ports }) => {
|
|
3
3
|
const port = ports[0];
|
|
4
4
|
port.onmessage = ({ data }) => {
|
|
5
|
-
const { nodes, nodeIds, idToPosition, rels, direction, packing, pixelRatio, forcedDelay = 0 } = data;
|
|
6
|
-
const layoutData = layout(nodes, nodeIds, idToPosition, rels, direction, packing, pixelRatio);
|
|
5
|
+
const { nodes, nodeIds, idToPosition, rels, direction, packing, pixelRatio, forcedDelay = 0, clusterAssignments } = data;
|
|
6
|
+
const layoutData = layout(nodes, nodeIds, idToPosition, rels, direction, packing, pixelRatio, clusterAssignments);
|
|
7
7
|
if (forcedDelay) {
|
|
8
8
|
setTimeout(() => {
|
|
9
9
|
port.postMessage(layoutData);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export function layout(nodes: any, nodeIds: any, idToPosition: any, rels: any, direction: any, packing: any, pixelRatio
|
|
1
|
+
export function layout(nodes: any, nodeIds: any, idToPosition: any, rels: any, direction: any, packing: any, pixelRatio: any, clusterAssignments: any): {
|
|
2
2
|
positions: {};
|
|
3
3
|
parents: {};
|
|
4
4
|
waypoints: {};
|
|
@@ -56,9 +56,11 @@ const getGraphDimensions = (g) => {
|
|
|
56
56
|
yOffset: minCenterY - minY
|
|
57
57
|
};
|
|
58
58
|
};
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
const SYNTHETIC_PARENT_PREFIX = 'syntheticParent:';
|
|
60
|
+
const toSyntheticParentNodeId = (clusterId) => `${SYNTHETIC_PARENT_PREFIX}${clusterId}`;
|
|
61
|
+
const createGraph = (pixelRatio, { compound = false } = {}) => {
|
|
62
|
+
// Create a new directed graph (compound when clusterBy assignments are provided)
|
|
63
|
+
const g = new dagre.graphlib.Graph(compound ? { compound: true } : undefined);
|
|
62
64
|
// Set an object for the graph label
|
|
63
65
|
g.setGraph({});
|
|
64
66
|
// Default to assigning a new object as a label for each new edge.
|
|
@@ -70,6 +72,24 @@ const createGraph = (pixelRatio) => {
|
|
|
70
72
|
g.graph().ranksep = 75 * pixelRatio;
|
|
71
73
|
return g;
|
|
72
74
|
};
|
|
75
|
+
const applySyntheticParents = (g, clusterAssignments) => {
|
|
76
|
+
if (!clusterAssignments) {
|
|
77
|
+
return new Set();
|
|
78
|
+
}
|
|
79
|
+
const createdSyntheticParents = new Set();
|
|
80
|
+
for (const [nodeId, clusterId] of Object.entries(clusterAssignments)) {
|
|
81
|
+
if (!g.hasNode(nodeId) || clusterId === undefined || clusterId === null) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const syntheticParentNodeId = toSyntheticParentNodeId(clusterId);
|
|
85
|
+
if (!createdSyntheticParents.has(syntheticParentNodeId)) {
|
|
86
|
+
g.setNode(syntheticParentNodeId, { width: 0, height: 0 });
|
|
87
|
+
createdSyntheticParents.add(syntheticParentNodeId);
|
|
88
|
+
}
|
|
89
|
+
g.setParent(nodeId, syntheticParentNodeId);
|
|
90
|
+
}
|
|
91
|
+
return createdSyntheticParents;
|
|
92
|
+
};
|
|
73
93
|
const findParentForEdges = (id, connectedNodes, layoutGraph) => {
|
|
74
94
|
const { rank: currentRank } = layoutGraph.node(id);
|
|
75
95
|
let pRank = null;
|
|
@@ -123,10 +143,14 @@ const getConnectedSubGraphs = (g, pixelRatio) => {
|
|
|
123
143
|
}
|
|
124
144
|
return subGraphs;
|
|
125
145
|
};
|
|
126
|
-
const layoutGraph = (g, direction, parents) => {
|
|
146
|
+
const layoutGraph = (g, direction, parents, syntheticParentNodeIds = new Set()) => {
|
|
127
147
|
g.graph().ranker = Ranker;
|
|
128
148
|
g.graph().rankdir = Directions[direction];
|
|
129
149
|
const dagreLayoutGraph = dagre.layout(g);
|
|
150
|
+
syntheticParentNodeIds.forEach((id) => {
|
|
151
|
+
dagreLayoutGraph.removeNode(id);
|
|
152
|
+
g.removeNode(id);
|
|
153
|
+
});
|
|
130
154
|
for (const id of dagreLayoutGraph.nodes()) {
|
|
131
155
|
const pId = findParent(id, dagreLayoutGraph);
|
|
132
156
|
if (pId !== null) {
|
|
@@ -158,8 +182,10 @@ const mergeStraightPoints = (points) => {
|
|
|
158
182
|
mergedPoints.push(points[points.length - 1]);
|
|
159
183
|
return mergedPoints;
|
|
160
184
|
};
|
|
161
|
-
export const layout = (nodes, nodeIds, idToPosition, rels, direction, packing, pixelRatio
|
|
162
|
-
const
|
|
185
|
+
export const layout = (nodes, nodeIds, idToPosition, rels, direction, packing, pixelRatio, clusterAssignments) => {
|
|
186
|
+
const resolvedPixelRatio = pixelRatio ?? 1;
|
|
187
|
+
const useClusters = Boolean(clusterAssignments && Object.keys(clusterAssignments).length > 0);
|
|
188
|
+
const g = createGraph(resolvedPixelRatio, { compound: useClusters });
|
|
163
189
|
const parents = {};
|
|
164
190
|
const positionSum = { x: 0, y: 0 };
|
|
165
191
|
const numNodes = nodes.length;
|
|
@@ -169,9 +195,10 @@ export const layout = (nodes, nodeIds, idToPosition, rels, direction, packing, p
|
|
|
169
195
|
const position = idToPosition[n.id];
|
|
170
196
|
positionSum.x += position?.x || 0;
|
|
171
197
|
positionSum.y += position?.y || 0;
|
|
172
|
-
const size = (n.size || DefaultNodeSize) * GlAdjust *
|
|
198
|
+
const size = (n.size || DefaultNodeSize) * GlAdjust * resolvedPixelRatio;
|
|
173
199
|
g.setNode(n.id, { width: size, height: size });
|
|
174
200
|
}
|
|
201
|
+
const syntheticParentNodeIds = useClusters ? applySyntheticParents(g, clusterAssignments) : new Set();
|
|
175
202
|
const prevNodeCenterPoint = numNodes ? [positionSum.x / numNodes, positionSum.y / numNodes] : [0, 0];
|
|
176
203
|
// Add edges to the graph.
|
|
177
204
|
const addedRel = {};
|
|
@@ -184,7 +211,9 @@ export const layout = (nodes, nodeIds, idToPosition, rels, direction, packing, p
|
|
|
184
211
|
}
|
|
185
212
|
}
|
|
186
213
|
}
|
|
187
|
-
|
|
214
|
+
// With clusterBy, lay out one compound graph so same-cluster nodes stay together
|
|
215
|
+
// even across disconnected components. Otherwise keep component packing.
|
|
216
|
+
const subGraphs = useClusters ? [g] : getConnectedSubGraphs(g, resolvedPixelRatio);
|
|
188
217
|
if (subGraphs.length > 1) {
|
|
189
218
|
subGraphs.forEach((subGraph) => layoutGraph(subGraph, direction, parents));
|
|
190
219
|
const isVertical = isDirectionVertical(direction);
|
|
@@ -316,7 +345,7 @@ export const layout = (nodes, nodeIds, idToPosition, rels, direction, packing, p
|
|
|
316
345
|
}
|
|
317
346
|
}
|
|
318
347
|
else {
|
|
319
|
-
layoutGraph(g, direction, parents);
|
|
348
|
+
layoutGraph(g, direction, parents, syntheticParentNodeIds);
|
|
320
349
|
}
|
|
321
350
|
positionSum.x = 0;
|
|
322
351
|
positionSum.y = 0;
|
|
@@ -33,4 +33,94 @@ describe('Dagre-layout-impl', () => {
|
|
|
33
33
|
expect(xs[i]).toBeGreaterThan(xs[i - 1]);
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
|
+
test('synthetic parent nodes are omitted from positions and animation parents', () => {
|
|
37
|
+
const nodes = [{ id: 'a' }, { id: 'b' }, { id: 'c' }];
|
|
38
|
+
const nodeIds = { a: { id: 'a' }, b: { id: 'b' }, c: { id: 'c' } };
|
|
39
|
+
const idToPosition = {
|
|
40
|
+
a: { id: 'a', x: 0, y: 0 },
|
|
41
|
+
b: { id: 'b', x: 0, y: 0 },
|
|
42
|
+
c: { id: 'c', x: 0, y: 0 }
|
|
43
|
+
};
|
|
44
|
+
const rels = [
|
|
45
|
+
{ id: 'ab', from: 'a', to: 'b' },
|
|
46
|
+
{ id: 'bc', from: 'b', to: 'c' }
|
|
47
|
+
];
|
|
48
|
+
const clusterAssignments = { a: 'group-1', b: 'group-1', c: 'group-2' };
|
|
49
|
+
const { positions, parents } = layout(nodes, nodeIds, idToPosition, rels, 'down', 'bin', 1, clusterAssignments);
|
|
50
|
+
expect(Object.keys(positions).sort()).toEqual(nodes.map(({ id }) => id).sort());
|
|
51
|
+
expect(Object.values(parents).every((id) => id in nodeIds)).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
test('clusterAssignments group same-cluster nodes', () => {
|
|
54
|
+
const categories = ['Person', 'Company', 'Product'];
|
|
55
|
+
const nodes = [];
|
|
56
|
+
const nodeIds = {};
|
|
57
|
+
const idToPosition = {};
|
|
58
|
+
const rels = [];
|
|
59
|
+
const clusterAssignments = {};
|
|
60
|
+
categories.forEach((category) => {
|
|
61
|
+
for (let i = 0; i < 4; i++) {
|
|
62
|
+
const id = `${category}-${i}`;
|
|
63
|
+
nodes.push({ id });
|
|
64
|
+
nodeIds[id] = { id };
|
|
65
|
+
idToPosition[id] = { id, x: 0, y: 0 };
|
|
66
|
+
clusterAssignments[id] = category;
|
|
67
|
+
if (i > 0) {
|
|
68
|
+
rels.push({ id: `${id}-prev`, from: `${category}-${i - 1}`, to: id });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
rels.push({ id: 'cross-1', from: 'Person-0', to: 'Company-0' });
|
|
73
|
+
rels.push({ id: 'cross-2', from: 'Company-3', to: 'Product-0' });
|
|
74
|
+
const { positions } = layout(nodes, nodeIds, idToPosition, rels, 'down', 'bin', 1, clusterAssignments);
|
|
75
|
+
expect(Object.keys(positions)).toHaveLength(nodes.length);
|
|
76
|
+
const centroid = (ids) => {
|
|
77
|
+
let x = 0;
|
|
78
|
+
let y = 0;
|
|
79
|
+
ids.forEach((id) => {
|
|
80
|
+
x += positions[id].x;
|
|
81
|
+
y += positions[id].y;
|
|
82
|
+
});
|
|
83
|
+
return { x: x / ids.length, y: y / ids.length };
|
|
84
|
+
};
|
|
85
|
+
const clusterIds = categories.map((category) => nodes.filter((node) => node.id.startsWith(`${category}-`)).map((node) => node.id));
|
|
86
|
+
const centroids = clusterIds.map(centroid);
|
|
87
|
+
// Same-cluster members should be closer to their own centroid than to other centroids on average
|
|
88
|
+
clusterIds.forEach((ids, clusterIndex) => {
|
|
89
|
+
const own = centroids[clusterIndex];
|
|
90
|
+
const avgOwn = ids.reduce((sum, id) => {
|
|
91
|
+
const dx = positions[id].x - own.x;
|
|
92
|
+
const dy = positions[id].y - own.y;
|
|
93
|
+
return sum + Math.hypot(dx, dy);
|
|
94
|
+
}, 0) / ids.length;
|
|
95
|
+
const otherDistances = centroids
|
|
96
|
+
.filter((_, index) => index !== clusterIndex)
|
|
97
|
+
.map((other) => Math.hypot(own.x - other.x, own.y - other.y));
|
|
98
|
+
const minOtherCentroid = Math.min(...otherDistances);
|
|
99
|
+
expect(avgOwn).toBeLessThan(minOtherCentroid);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
test('omitting clusterAssignments keeps the non-compound packing path', () => {
|
|
103
|
+
const nodes = [{ id: 'a' }, { id: 'b' }, { id: 'c' }, { id: 'd' }];
|
|
104
|
+
const nodeIds = {
|
|
105
|
+
a: { id: 'a' },
|
|
106
|
+
b: { id: 'b' },
|
|
107
|
+
c: { id: 'c' },
|
|
108
|
+
d: { id: 'd' }
|
|
109
|
+
};
|
|
110
|
+
const idToPosition = {
|
|
111
|
+
a: { id: 'a', x: 0, y: 0 },
|
|
112
|
+
b: { id: 'b', x: 0, y: 0 },
|
|
113
|
+
c: { id: 'c', x: 0, y: 0 },
|
|
114
|
+
d: { id: 'd', x: 0, y: 0 }
|
|
115
|
+
};
|
|
116
|
+
// Two disconnected components
|
|
117
|
+
const rels = [
|
|
118
|
+
{ id: 'ab', from: 'a', to: 'b' },
|
|
119
|
+
{ id: 'cd', from: 'c', to: 'd' }
|
|
120
|
+
];
|
|
121
|
+
const { positions } = layout(nodes, nodeIds, idToPosition, rels, 'down', 'bin', 1);
|
|
122
|
+
expect(Object.keys(positions)).toHaveLength(4);
|
|
123
|
+
expect(positions.a).toBeDefined();
|
|
124
|
+
expect(positions.d).toBeDefined();
|
|
125
|
+
});
|
|
36
126
|
});
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { createCoseBilkentLayoutWorker } from './cosebilkent-layout/workerFactory.mjs';
|
|
2
1
|
import { createHierarchicalLayoutWorker } from './hierarchical-layout/workerFactory.mjs';
|
|
3
2
|
import { hierarchicalLayoutFallbackWorker } from './hierarchical-layout/HierarchicalLayout.fallback.js';
|
|
4
|
-
|
|
5
|
-
export { createCoseBilkentLayoutWorker, createHierarchicalLayoutWorker, hierarchicalLayoutFallbackWorker, coseBilkentLayoutFallbackWorker };
|
|
3
|
+
export { createHierarchicalLayoutWorker, hierarchicalLayoutFallbackWorker };
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { coseBilkentLayoutFallbackWorker } from './cosebilkent-layout/CoseBilkentLayout.fallback.js';
|
|
2
|
-
import { createCoseBilkentLayoutWorker } from './cosebilkent-layout/workerFactory.mjs';
|
|
3
1
|
import { hierarchicalLayoutFallbackWorker } from './hierarchical-layout/HierarchicalLayout.fallback.js';
|
|
4
2
|
import { createHierarchicalLayoutWorker } from './hierarchical-layout/workerFactory.mjs';
|
|
5
|
-
export {
|
|
3
|
+
export { createHierarchicalLayoutWorker, hierarchicalLayoutFallbackWorker };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neo4j-nvl/layout-workers",
|
|
3
|
-
"version": "1.2.0-
|
|
3
|
+
"version": "1.2.0-dbc13ec2",
|
|
4
4
|
"license": "SEE LICENSE IN 'LICENSE.txt'",
|
|
5
5
|
"description": "Layout workers for the Neo4j Visualization Library",
|
|
6
6
|
"keywords": [
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"watch": "yarn global:tsc -w",
|
|
23
23
|
"prepack": "cp ../../LICENSE.txt ./",
|
|
24
24
|
"postpack": "rm LICENSE.txt",
|
|
25
|
-
"eslint": "yarn global:eslint ./src/ --ext .js,.mjs"
|
|
25
|
+
"eslint": "yarn global:eslint ./src/ --ext .js,.mjs",
|
|
26
|
+
"test": "NODE_OPTIONS=--experimental-vm-modules yarn global:jest"
|
|
26
27
|
},
|
|
27
28
|
"typedoc": {
|
|
28
29
|
"entryPoint": "./src/index.js",
|
|
@@ -33,8 +34,6 @@
|
|
|
33
34
|
"dependencies": {
|
|
34
35
|
"@neo4j-bloom/dagre": "0.8.14",
|
|
35
36
|
"bin-pack": "1.0.2",
|
|
36
|
-
"cytoscape": "3.33.1",
|
|
37
|
-
"cytoscape-cose-bilkent": "4.1.0",
|
|
38
37
|
"graphlib": "2.1.8"
|
|
39
38
|
},
|
|
40
39
|
"devDependencies": {
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
2
|
-
/* eslint-disable no-empty-function */
|
|
3
|
-
import { layout } from './cose-bilkent-layout-impl.js';
|
|
4
|
-
class CoseBilkentLayoutFallbackWorker {
|
|
5
|
-
start() { }
|
|
6
|
-
postMessage(data) {
|
|
7
|
-
const { elements, spacingFactor } = data;
|
|
8
|
-
const layoutData = layout(elements, spacingFactor);
|
|
9
|
-
this.onmessage({ data: layoutData });
|
|
10
|
-
}
|
|
11
|
-
onmessage() { }
|
|
12
|
-
close() { }
|
|
13
|
-
}
|
|
14
|
-
export const coseBilkentLayoutFallbackWorker = {
|
|
15
|
-
port: new CoseBilkentLayoutFallbackWorker()
|
|
16
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { layout } from './cose-bilkent-layout-impl.js';
|
|
2
|
-
onconnect = ({ ports }) => {
|
|
3
|
-
const port = ports[0];
|
|
4
|
-
port.onmessage = ({ data }) => {
|
|
5
|
-
const { elements, spacingFactor } = data;
|
|
6
|
-
const layoutData = layout(elements, spacingFactor);
|
|
7
|
-
port.postMessage(layoutData);
|
|
8
|
-
};
|
|
9
|
-
};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import cytoscape from 'cytoscape';
|
|
2
|
-
import coseBilkent from 'cytoscape-cose-bilkent';
|
|
3
|
-
cytoscape.use(coseBilkent);
|
|
4
|
-
const type = 'cose-bilkent';
|
|
5
|
-
export const layout = (elements, spacingFactor) => {
|
|
6
|
-
const c = cytoscape({
|
|
7
|
-
headless: true,
|
|
8
|
-
styleEnabled: false
|
|
9
|
-
});
|
|
10
|
-
c.add(elements);
|
|
11
|
-
const positions = {};
|
|
12
|
-
const cytoLayout = c.layout({
|
|
13
|
-
name: type,
|
|
14
|
-
animate: false,
|
|
15
|
-
spacingFactor,
|
|
16
|
-
quality: 'default',
|
|
17
|
-
tile: false,
|
|
18
|
-
randomize: true,
|
|
19
|
-
stop: () => {
|
|
20
|
-
c.nodes().forEach((n) => {
|
|
21
|
-
positions[n.id()] = { ...n.position() };
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
cytoLayout.run();
|
|
26
|
-
return {
|
|
27
|
-
positions
|
|
28
|
-
};
|
|
29
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export function createCoseBilkentLayoutWorker(): SharedWorker;
|