@antv/layout 2.0.0-alpha.2 → 2.0.0-alpha.3
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/index.js +1202 -1239
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +2 -2
- package/dist/index.min.js.map +1 -1
- package/dist/worker.js +1 -1
- package/dist/worker.js.map +1 -1
- package/lib/algorithm/antv-dagre/index.js +10 -8
- package/lib/algorithm/antv-dagre/index.js.map +1 -1
- package/lib/algorithm/antv-dagre/types.d.ts +25 -3
- package/lib/algorithm/base-layout.d.ts +1 -0
- package/lib/algorithm/base-layout.js +5 -3
- package/lib/algorithm/base-layout.js.map +1 -1
- package/lib/algorithm/d3-force/index.d.ts +2 -2
- package/lib/algorithm/d3-force/index.js +59 -97
- package/lib/algorithm/d3-force/index.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/util/object.d.ts +1 -2
- package/lib/util/object.js +1 -4
- package/lib/util/object.js.map +1 -1
- package/lib/worker.js +763 -799
- package/lib/worker.js.map +1 -1
- package/package.json +1 -1
- package/src/algorithm/antv-dagre/index.ts +11 -12
- package/src/algorithm/antv-dagre/types.ts +25 -3
- package/src/algorithm/base-layout.ts +13 -8
- package/src/algorithm/d3-force/index.ts +67 -117
- package/src/util/object.ts +0 -4
package/dist/index.js
CHANGED
|
@@ -357,1195 +357,1257 @@
|
|
|
357
357
|
return result;
|
|
358
358
|
});
|
|
359
359
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}
|
|
377
|
-
node(id) {
|
|
378
|
-
return this.nodeMap.get(id);
|
|
379
|
-
}
|
|
380
|
-
nodeAt(index) {
|
|
381
|
-
if (!this.indexNodeCache) {
|
|
382
|
-
this.buildNodeIndexCache();
|
|
383
|
-
}
|
|
384
|
-
const nodeId = this.indexNodeCache.get(index);
|
|
385
|
-
return nodeId ? this.nodeMap.get(nodeId) : undefined;
|
|
386
|
-
}
|
|
387
|
-
nodeIndexOf(id) {
|
|
388
|
-
var _a;
|
|
389
|
-
if (!this.nodeIndexCache) {
|
|
390
|
-
this.buildNodeIndexCache();
|
|
391
|
-
}
|
|
392
|
-
return (_a = this.nodeIndexCache.get(id)) !== null && _a !== void 0 ? _a : -1;
|
|
393
|
-
}
|
|
394
|
-
firstNode() {
|
|
395
|
-
return this.nodeMap.values().next().value;
|
|
396
|
-
}
|
|
397
|
-
forEachNode(callback) {
|
|
398
|
-
let i = 0;
|
|
399
|
-
this.nodeMap.forEach((node) => callback(node, i++));
|
|
400
|
-
}
|
|
401
|
-
originalNode(id) {
|
|
402
|
-
const node = this.nodeMap.get(id);
|
|
403
|
-
return node === null || node === void 0 ? void 0 : node._original;
|
|
404
|
-
}
|
|
405
|
-
nodeCount() {
|
|
406
|
-
return this.nodeMap.size;
|
|
407
|
-
}
|
|
408
|
-
edges() {
|
|
409
|
-
return Array.from(this.edgeMap.values());
|
|
410
|
-
}
|
|
411
|
-
edge(id) {
|
|
412
|
-
return this.edgeMap.get(id);
|
|
413
|
-
}
|
|
414
|
-
firstEdge() {
|
|
415
|
-
return this.edgeMap.values().next().value;
|
|
416
|
-
}
|
|
417
|
-
forEachEdge(callback) {
|
|
418
|
-
let i = 0;
|
|
419
|
-
this.edgeMap.forEach((edge) => callback(edge, i++));
|
|
420
|
-
}
|
|
421
|
-
originalEdge(id) {
|
|
422
|
-
const edge = this.edgeMap.get(id);
|
|
423
|
-
return edge === null || edge === void 0 ? void 0 : edge._original;
|
|
424
|
-
}
|
|
425
|
-
edgeCount() {
|
|
426
|
-
return this.edgeMap.size;
|
|
427
|
-
}
|
|
428
|
-
getEdgeId(edge) {
|
|
429
|
-
if (edge.id)
|
|
430
|
-
return edge.id;
|
|
431
|
-
const baseId = `${edge.source}-${edge.target}`;
|
|
432
|
-
const count = this.edgeIdCounter.get(baseId) || 0;
|
|
433
|
-
const id = count === 0 ? baseId : `${baseId}-${count}`;
|
|
434
|
-
this.edgeIdCounter.set(baseId, count + 1);
|
|
435
|
-
return id;
|
|
436
|
-
}
|
|
437
|
-
degree(nodeId, direction = 'both') {
|
|
438
|
-
if (!this.degreeCache) {
|
|
439
|
-
this.buildDegreeCache();
|
|
440
|
-
}
|
|
441
|
-
const degree = this.degreeCache.get(nodeId);
|
|
442
|
-
if (!degree)
|
|
443
|
-
return 0;
|
|
444
|
-
return degree[direction];
|
|
445
|
-
}
|
|
446
|
-
neighbors(nodeId, direction = 'both') {
|
|
447
|
-
if (!this.outAdjacencyCache || !this.inAdjacencyCache) {
|
|
448
|
-
this.buildAdjacencyCache();
|
|
449
|
-
}
|
|
450
|
-
if (direction === 'out') {
|
|
451
|
-
return Array.from(this.outAdjacencyCache.get(nodeId) || []);
|
|
452
|
-
}
|
|
453
|
-
if (direction === 'in') {
|
|
454
|
-
return Array.from(this.inAdjacencyCache.get(nodeId) || []);
|
|
455
|
-
}
|
|
456
|
-
if (this.bothAdjacencyCache) {
|
|
457
|
-
return Array.from(this.bothAdjacencyCache.get(nodeId) || []);
|
|
360
|
+
const isArray = Array.isArray;
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Return the layout result for a graph with zero or one node.
|
|
364
|
+
* @param graph original graph
|
|
365
|
+
* @param center the layout center
|
|
366
|
+
* @returns layout result
|
|
367
|
+
*/
|
|
368
|
+
function applySingleNodeLayout(model, center, dimensions = 2) {
|
|
369
|
+
const n = model.nodeCount();
|
|
370
|
+
if (n === 1) {
|
|
371
|
+
const first = model.firstNode();
|
|
372
|
+
first.x = center[0];
|
|
373
|
+
first.y = center[1];
|
|
374
|
+
if (dimensions === 3) {
|
|
375
|
+
first.z = center[2] || 0;
|
|
458
376
|
}
|
|
459
|
-
const inSet = this.inAdjacencyCache.get(nodeId);
|
|
460
|
-
const outSet = this.outAdjacencyCache.get(nodeId);
|
|
461
|
-
if (!inSet && !outSet)
|
|
462
|
-
return [];
|
|
463
|
-
if (!inSet)
|
|
464
|
-
return Array.from(outSet);
|
|
465
|
-
if (!outSet)
|
|
466
|
-
return Array.from(inSet);
|
|
467
|
-
const merged = new Set();
|
|
468
|
-
inSet.forEach((id) => merged.add(id));
|
|
469
|
-
outSet.forEach((id) => merged.add(id));
|
|
470
|
-
return Array.from(merged);
|
|
471
|
-
}
|
|
472
|
-
successors(nodeId) {
|
|
473
|
-
return this.neighbors(nodeId, 'out');
|
|
474
|
-
}
|
|
475
|
-
predecessors(nodeId) {
|
|
476
|
-
return this.neighbors(nodeId, 'in');
|
|
477
|
-
}
|
|
478
|
-
setNodeOrder(nodes) {
|
|
479
|
-
const next = new Map();
|
|
480
|
-
for (const node of nodes)
|
|
481
|
-
next.set(node.id, node);
|
|
482
|
-
this.nodeMap = next;
|
|
483
|
-
this.nodeIndexCache = undefined;
|
|
484
|
-
this.indexNodeCache = undefined;
|
|
485
|
-
}
|
|
486
|
-
clearCache() {
|
|
487
|
-
this.degreeCache = undefined;
|
|
488
|
-
this.inAdjacencyCache = undefined;
|
|
489
|
-
this.outAdjacencyCache = undefined;
|
|
490
|
-
this.bothAdjacencyCache = undefined;
|
|
491
|
-
this.nodeIndexCache = undefined;
|
|
492
|
-
this.indexNodeCache = undefined;
|
|
493
377
|
}
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
if (!this.degreeCache.has(target)) {
|
|
509
|
-
this.degreeCache.set(target, { in: 0, out: 0, both: 0 });
|
|
510
|
-
}
|
|
511
|
-
const targetDeg = this.degreeCache.get(edge.target);
|
|
512
|
-
if (targetDeg) {
|
|
513
|
-
targetDeg.in++;
|
|
514
|
-
targetDeg.both++;
|
|
515
|
-
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Floyd-Warshall algorithm to find shortest paths (but with no negative cycles).
|
|
382
|
+
*/
|
|
383
|
+
const floydWarshall = (adjMatrix) => {
|
|
384
|
+
// initialize
|
|
385
|
+
const n = adjMatrix.length;
|
|
386
|
+
const dist = Array.from({ length: n }, () => new Array(n));
|
|
387
|
+
for (let i = 0; i < n; i++) {
|
|
388
|
+
const row = adjMatrix[i];
|
|
389
|
+
const drow = dist[i];
|
|
390
|
+
for (let j = 0; j < n; j++) {
|
|
391
|
+
drow[j] = i === j ? 0 : row[j] > 0 ? row[j] : Infinity;
|
|
516
392
|
}
|
|
517
393
|
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
for (
|
|
522
|
-
|
|
394
|
+
// floyd
|
|
395
|
+
for (let k = 0; k < n; k++) {
|
|
396
|
+
const dk = dist[k];
|
|
397
|
+
for (let i = 0; i < n; i++) {
|
|
398
|
+
const di = dist[i];
|
|
399
|
+
const dik = di[k];
|
|
400
|
+
if (dik === Infinity)
|
|
523
401
|
continue;
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
402
|
+
for (let j = 0; j < n; j++) {
|
|
403
|
+
const dkj = dk[j];
|
|
404
|
+
if (dkj === Infinity)
|
|
405
|
+
continue;
|
|
406
|
+
const next = dik + dkj;
|
|
407
|
+
if (next < di[j]) {
|
|
408
|
+
di[j] = next;
|
|
409
|
+
}
|
|
530
410
|
}
|
|
531
|
-
this.inAdjacencyCache.get(edge.target).add(edge.source);
|
|
532
411
|
}
|
|
533
412
|
}
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
'vx',
|
|
557
|
-
'vy',
|
|
558
|
-
'vz',
|
|
559
|
-
'fx',
|
|
560
|
-
'fy',
|
|
561
|
-
'fz',
|
|
562
|
-
'parentId',
|
|
563
|
-
];
|
|
564
|
-
const edgeFields = ['id', 'source', 'target', 'points'];
|
|
565
|
-
function extractNodeData(nodes, node) {
|
|
566
|
-
if (!nodes) {
|
|
567
|
-
throw new Error('Data.nodes is required');
|
|
568
|
-
}
|
|
569
|
-
const result = new Map();
|
|
570
|
-
for (const datum of nodes) {
|
|
571
|
-
const nodeData = { _original: datum };
|
|
572
|
-
for (const field of nodeFields) {
|
|
573
|
-
const value = datum[field];
|
|
574
|
-
if (isNil(value))
|
|
575
|
-
continue;
|
|
576
|
-
nodeData[field] = value;
|
|
577
|
-
}
|
|
578
|
-
if (node) {
|
|
579
|
-
const customFields = node(datum);
|
|
580
|
-
for (const key in customFields) {
|
|
581
|
-
const value = customFields[key];
|
|
582
|
-
if (isNil(value))
|
|
583
|
-
continue;
|
|
584
|
-
nodeData[key] = value;
|
|
585
|
-
}
|
|
413
|
+
return dist;
|
|
414
|
+
};
|
|
415
|
+
/**
|
|
416
|
+
* Get the adjacency matrix of the graph model.
|
|
417
|
+
*/
|
|
418
|
+
const getAdjMatrix = (model, directed) => {
|
|
419
|
+
const n = model.nodeCount();
|
|
420
|
+
const matrix = Array.from({ length: n }, () => new Array(n));
|
|
421
|
+
// map node with index in data.nodes
|
|
422
|
+
const nodeMap = {};
|
|
423
|
+
let i = 0;
|
|
424
|
+
model.forEachNode((node) => {
|
|
425
|
+
nodeMap[node.id] = i++;
|
|
426
|
+
});
|
|
427
|
+
model.forEachEdge((e) => {
|
|
428
|
+
const sIndex = nodeMap[e.source];
|
|
429
|
+
const tIndex = nodeMap[e.target];
|
|
430
|
+
if (sIndex === undefined || tIndex === undefined)
|
|
431
|
+
return;
|
|
432
|
+
matrix[sIndex][tIndex] = 1;
|
|
433
|
+
if (!directed) {
|
|
434
|
+
matrix[tIndex][sIndex] = 1;
|
|
586
435
|
}
|
|
587
|
-
|
|
588
|
-
|
|
436
|
+
});
|
|
437
|
+
return matrix;
|
|
438
|
+
};
|
|
439
|
+
/**
|
|
440
|
+
* Get the adjacency list of the graph model.
|
|
441
|
+
*/
|
|
442
|
+
const getAdjList = (model, directed) => {
|
|
443
|
+
const n = model.nodeCount();
|
|
444
|
+
const adjList = Array.from({ length: n }, () => []);
|
|
445
|
+
// map node with index
|
|
446
|
+
const nodeMap = {};
|
|
447
|
+
let idx = 0;
|
|
448
|
+
model.forEachNode((node) => {
|
|
449
|
+
nodeMap[node.id] = idx++;
|
|
450
|
+
});
|
|
451
|
+
model.forEachEdge((e) => {
|
|
452
|
+
const s = nodeMap[e.source];
|
|
453
|
+
const t = nodeMap[e.target];
|
|
454
|
+
if (s == null || t == null)
|
|
455
|
+
return;
|
|
456
|
+
adjList[s].push(t);
|
|
457
|
+
if (!directed)
|
|
458
|
+
adjList[t].push(s);
|
|
459
|
+
});
|
|
460
|
+
return adjList;
|
|
461
|
+
};
|
|
462
|
+
/**
|
|
463
|
+
* scale matrix
|
|
464
|
+
* @param matrix [ [], [], [] ]
|
|
465
|
+
* @param ratio
|
|
466
|
+
*/
|
|
467
|
+
const scaleMatrix = (matrix, ratio) => {
|
|
468
|
+
const n = matrix.length;
|
|
469
|
+
const result = new Array(n);
|
|
470
|
+
for (let i = 0; i < n; i++) {
|
|
471
|
+
const row = matrix[i];
|
|
472
|
+
const m = row.length;
|
|
473
|
+
const newRow = new Array(m);
|
|
474
|
+
for (let j = 0; j < m; j++) {
|
|
475
|
+
newRow[j] = row[j] * ratio;
|
|
589
476
|
}
|
|
590
|
-
result
|
|
477
|
+
result[i] = newRow;
|
|
591
478
|
}
|
|
592
479
|
return result;
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
continue;
|
|
610
|
-
edgeData[key] = value;
|
|
611
|
-
}
|
|
480
|
+
};
|
|
481
|
+
/**
|
|
482
|
+
* calculate the bounding box for the nodes according to their x, y, and size
|
|
483
|
+
* @param nodes nodes in the layout
|
|
484
|
+
* @returns
|
|
485
|
+
*/
|
|
486
|
+
const getLayoutBBox = (nodes) => {
|
|
487
|
+
let minX = Infinity;
|
|
488
|
+
let minY = Infinity;
|
|
489
|
+
let maxX = -Infinity;
|
|
490
|
+
let maxY = -Infinity;
|
|
491
|
+
nodes.forEach((node) => {
|
|
492
|
+
let size = node.data.size;
|
|
493
|
+
if (isArray(size)) {
|
|
494
|
+
if (size.length === 1)
|
|
495
|
+
size = [size[0], size[0]];
|
|
612
496
|
}
|
|
613
|
-
if (
|
|
614
|
-
|
|
497
|
+
else if (size === undefined || isNaN(size)) {
|
|
498
|
+
size = [30, 30];
|
|
615
499
|
}
|
|
616
|
-
if (
|
|
617
|
-
|
|
500
|
+
else if (isNumber(size)) {
|
|
501
|
+
size = [size, size];
|
|
618
502
|
}
|
|
619
|
-
|
|
503
|
+
const halfSize = [size[0] / 2, size[1] / 2];
|
|
504
|
+
const left = node.data.x - halfSize[0];
|
|
505
|
+
const right = node.data.x + halfSize[0];
|
|
506
|
+
const top = node.data.y - halfSize[1];
|
|
507
|
+
const bottom = node.data.y + halfSize[1];
|
|
508
|
+
if (minX > left)
|
|
509
|
+
minX = left;
|
|
510
|
+
if (minY > top)
|
|
511
|
+
minY = top;
|
|
512
|
+
if (maxX < right)
|
|
513
|
+
maxX = right;
|
|
514
|
+
if (maxY < bottom)
|
|
515
|
+
maxY = bottom;
|
|
516
|
+
});
|
|
517
|
+
return { minX, minY, maxX, maxY };
|
|
518
|
+
};
|
|
519
|
+
/**
|
|
520
|
+
* calculate the euclidean distance form p1 to p2
|
|
521
|
+
* @param p1
|
|
522
|
+
* @param p2
|
|
523
|
+
* @returns
|
|
524
|
+
*/
|
|
525
|
+
const getEuclideanDistance = (p1, p2) => Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
|
|
526
|
+
/**
|
|
527
|
+
* Depth first search begin from nodes in graphCore data.
|
|
528
|
+
* @param graphCore graphlib data structure
|
|
529
|
+
* @param nodes begin nodes
|
|
530
|
+
* @param fn will be called while visiting each node
|
|
531
|
+
* @param mode 'TB' - visit from top to bottom; 'BT' - visit from bottom to top;
|
|
532
|
+
* @returns
|
|
533
|
+
*/
|
|
534
|
+
const graphTreeDfs = (graph, nodes, fn, mode = 'TB', treeKey, stopFns = {}) => {
|
|
535
|
+
if (!(nodes === null || nodes === void 0 ? void 0 : nodes.length))
|
|
536
|
+
return;
|
|
537
|
+
const { stopBranchFn, stopAllFn } = stopFns;
|
|
538
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
539
|
+
const node = nodes[i];
|
|
540
|
+
if (!graph.hasNode(node.id))
|
|
541
|
+
continue;
|
|
542
|
+
if (stopBranchFn === null || stopBranchFn === void 0 ? void 0 : stopBranchFn(node))
|
|
543
|
+
continue; // Stop this branch
|
|
544
|
+
if (stopAllFn === null || stopAllFn === void 0 ? void 0 : stopAllFn(node))
|
|
545
|
+
return; // Stop all
|
|
546
|
+
if (mode === 'TB')
|
|
547
|
+
fn(node); // Traverse from top to bottom
|
|
548
|
+
graphTreeDfs(graph, graph.getChildren(node.id, treeKey), fn, mode, treeKey, stopFns);
|
|
549
|
+
if (mode !== 'TB')
|
|
550
|
+
fn(node); // Traverse from bottom to top
|
|
620
551
|
}
|
|
621
|
-
|
|
552
|
+
};
|
|
553
|
+
/**
|
|
554
|
+
* Use Johnson + Dijkstra to compute APSP for sparse graph.
|
|
555
|
+
* Fully compatible with floydWarshall(adjMatrix).
|
|
556
|
+
*/
|
|
557
|
+
function johnson(adjList) {
|
|
558
|
+
const n = adjList.length;
|
|
559
|
+
// Step 1: add a dummy node q connected to all nodes with weight 0
|
|
560
|
+
new Array(n).fill(0);
|
|
561
|
+
// Bellman-Ford to compute potentials h(v)
|
|
562
|
+
// 因为权重全是 1,无负边,可直接跳过 BF,h 全 0 即可
|
|
563
|
+
// Step 2: reweight edges
|
|
564
|
+
// 因为 h(u)=h(v)=0,reweight 后仍然是 1,省略 reweight 过程
|
|
565
|
+
// Step 3: run Dijkstra from each node
|
|
566
|
+
const distAll = Array.from({ length: n }, () => new Array(n).fill(Infinity));
|
|
567
|
+
for (let s = 0; s < n; s++) {
|
|
568
|
+
distAll[s] = dijkstra(adjList, s);
|
|
569
|
+
}
|
|
570
|
+
return distAll;
|
|
622
571
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
572
|
+
/**
|
|
573
|
+
* Dijkstra algorithm to find shortest paths from source to all nodes.
|
|
574
|
+
*/
|
|
575
|
+
function dijkstra(adjList, source) {
|
|
576
|
+
const n = adjList.length;
|
|
577
|
+
const dist = new Array(n).fill(Infinity);
|
|
578
|
+
dist[source] = 0;
|
|
579
|
+
// Minimal binary heap
|
|
580
|
+
const heap = new MinHeap();
|
|
581
|
+
heap.push([0, source]); // [distance, node]
|
|
582
|
+
while (!heap.empty()) {
|
|
583
|
+
const [d, u] = heap.pop();
|
|
584
|
+
if (d !== dist[u])
|
|
585
|
+
continue;
|
|
586
|
+
const neighbors = adjList[u];
|
|
587
|
+
for (let i = 0; i < neighbors.length; i++) {
|
|
588
|
+
const v = neighbors[i];
|
|
589
|
+
const nd = d + 1;
|
|
590
|
+
if (nd < dist[v]) {
|
|
591
|
+
dist[v] = nd;
|
|
592
|
+
heap.push([nd, v]);
|
|
593
|
+
}
|
|
633
594
|
}
|
|
634
|
-
}
|
|
595
|
+
}
|
|
596
|
+
return dist;
|
|
635
597
|
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
this.graph = new GraphLib(data, options);
|
|
598
|
+
class MinHeap {
|
|
599
|
+
constructor() {
|
|
600
|
+
this.data = [];
|
|
640
601
|
}
|
|
641
|
-
|
|
642
|
-
|
|
602
|
+
push(item) {
|
|
603
|
+
this.data.push(item);
|
|
604
|
+
this.bubbleUp(this.data.length - 1);
|
|
643
605
|
}
|
|
644
|
-
|
|
645
|
-
this.
|
|
606
|
+
pop() {
|
|
607
|
+
const top = this.data[0];
|
|
608
|
+
const end = this.data.pop();
|
|
609
|
+
if (this.data.length > 0) {
|
|
610
|
+
this.data[0] = end;
|
|
611
|
+
this.bubbleDown(0);
|
|
612
|
+
}
|
|
613
|
+
return top;
|
|
646
614
|
}
|
|
647
|
-
|
|
648
|
-
this.
|
|
615
|
+
empty() {
|
|
616
|
+
return this.data.length === 0;
|
|
649
617
|
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
618
|
+
bubbleUp(pos) {
|
|
619
|
+
const data = this.data;
|
|
620
|
+
while (pos > 0) {
|
|
621
|
+
const parent = (pos - 1) >> 1;
|
|
622
|
+
if (data[parent][0] <= data[pos][0])
|
|
623
|
+
break;
|
|
624
|
+
[data[parent], data[pos]] = [data[pos], data[parent]];
|
|
625
|
+
pos = parent;
|
|
626
|
+
}
|
|
656
627
|
}
|
|
657
|
-
|
|
658
|
-
this.
|
|
628
|
+
bubbleDown(pos) {
|
|
629
|
+
const data = this.data;
|
|
630
|
+
const length = data.length;
|
|
631
|
+
while (true) {
|
|
632
|
+
const left = pos * 2 + 1;
|
|
633
|
+
const right = pos * 2 + 2;
|
|
634
|
+
let min = pos;
|
|
635
|
+
if (left < length && data[left][0] < data[min][0])
|
|
636
|
+
min = left;
|
|
637
|
+
if (right < length && data[right][0] < data[min][0])
|
|
638
|
+
min = right;
|
|
639
|
+
if (min === pos)
|
|
640
|
+
break;
|
|
641
|
+
[data[pos], data[min]] = [data[min], data[pos]];
|
|
642
|
+
pos = min;
|
|
643
|
+
}
|
|
659
644
|
}
|
|
660
645
|
}
|
|
661
646
|
|
|
662
647
|
/**
|
|
663
|
-
*
|
|
664
|
-
*
|
|
665
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
648
|
+
* Get nested property value
|
|
649
|
+
* For example: getNestedValue(obj, 'a.b.c') will return obj.a.b.c
|
|
666
650
|
*/
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
const throwMarker = Symbol("Comlink.thrown");
|
|
672
|
-
const isObject = (val) => (typeof val === "object" && val !== null) || typeof val === "function";
|
|
651
|
+
function getNestedValue(obj, path) {
|
|
652
|
+
const keys = String(path).split('.');
|
|
653
|
+
return get$1(obj, keys);
|
|
654
|
+
}
|
|
673
655
|
/**
|
|
674
|
-
*
|
|
656
|
+
* Set nested property value
|
|
657
|
+
* For example: setNestedValue(obj, 'a.b.c', value) will set obj.a.b.c = value
|
|
675
658
|
*/
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
expose(obj, port1);
|
|
681
|
-
return [port2, [port2]];
|
|
682
|
-
},
|
|
683
|
-
deserialize(port) {
|
|
684
|
-
port.start();
|
|
685
|
-
return wrap(port);
|
|
686
|
-
},
|
|
687
|
-
};
|
|
659
|
+
function setNestedValue(obj, path, value) {
|
|
660
|
+
const keys = String(path).split('.');
|
|
661
|
+
set$1(obj, keys, value);
|
|
662
|
+
}
|
|
688
663
|
/**
|
|
689
|
-
*
|
|
664
|
+
* Merge objects, but undefined values in source objects will not override existing values
|
|
665
|
+
* @param target - The target object
|
|
666
|
+
* @param sources - Source objects to merge
|
|
667
|
+
* @returns A new merged object
|
|
668
|
+
*
|
|
669
|
+
* @example
|
|
670
|
+
* assignDefined({ a: 1, b: 2 }, { b: undefined, c: 3 })
|
|
671
|
+
* // Returns: { a: 1, b: 2, c: 3 }
|
|
690
672
|
*/
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
name: value.name,
|
|
701
|
-
stack: value.stack,
|
|
702
|
-
},
|
|
703
|
-
};
|
|
704
|
-
}
|
|
705
|
-
else {
|
|
706
|
-
serialized = { isError: false, value };
|
|
707
|
-
}
|
|
708
|
-
return [serialized, []];
|
|
709
|
-
},
|
|
710
|
-
deserialize(serialized) {
|
|
711
|
-
if (serialized.isError) {
|
|
712
|
-
throw Object.assign(new Error(serialized.value.message), serialized.value);
|
|
673
|
+
function assignDefined(target, ...sources) {
|
|
674
|
+
sources.forEach((source) => {
|
|
675
|
+
if (source) {
|
|
676
|
+
Object.keys(source).forEach((key) => {
|
|
677
|
+
const value = source[key];
|
|
678
|
+
if (value !== undefined) {
|
|
679
|
+
target[key] = value;
|
|
680
|
+
}
|
|
681
|
+
});
|
|
713
682
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
}
|
|
683
|
+
});
|
|
684
|
+
return target;
|
|
685
|
+
}
|
|
686
|
+
|
|
717
687
|
/**
|
|
718
|
-
*
|
|
688
|
+
* 通用排序核心函数
|
|
719
689
|
*/
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
for (const allowedOrigin of allowedOrigins) {
|
|
726
|
-
if (origin === allowedOrigin || allowedOrigin === "*") {
|
|
727
|
-
return true;
|
|
728
|
-
}
|
|
729
|
-
if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {
|
|
730
|
-
return true;
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
return false;
|
|
690
|
+
function sort$1(model, compareFn) {
|
|
691
|
+
const nodes = model.nodes();
|
|
692
|
+
nodes.sort(compareFn);
|
|
693
|
+
model.setNodeOrder(nodes);
|
|
694
|
+
return model;
|
|
734
695
|
}
|
|
735
|
-
function
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
696
|
+
function orderByDegree(model) {
|
|
697
|
+
return sort$1(model, (nodeA, nodeB) => {
|
|
698
|
+
const degreeA = model.degree(nodeA.id);
|
|
699
|
+
const degreeB = model.degree(nodeB.id);
|
|
700
|
+
return degreeB - degreeA; // descending order
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* 按 ID 排序
|
|
705
|
+
*/
|
|
706
|
+
function orderById(model) {
|
|
707
|
+
return sort$1(model, (nodeA, nodeB) => {
|
|
708
|
+
const idA = nodeA.id;
|
|
709
|
+
const idB = nodeB.id;
|
|
710
|
+
if (typeof idA === 'number' && typeof idB === 'number') {
|
|
711
|
+
return idA - idB;
|
|
743
712
|
}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
}
|
|
784
|
-
break;
|
|
785
|
-
default:
|
|
786
|
-
return;
|
|
713
|
+
return String(idA).localeCompare(String(idB));
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* 按自定义比较函数排序
|
|
718
|
+
*/
|
|
719
|
+
function orderBySorter(model, sorter) {
|
|
720
|
+
return sort$1(model, (nodeA, nodeB) => {
|
|
721
|
+
const a = model.originalNode(nodeA.id);
|
|
722
|
+
const b = model.originalNode(nodeB.id);
|
|
723
|
+
return sorter(a, b);
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Order nodes according to graph topology
|
|
728
|
+
*/
|
|
729
|
+
function orderByTopology(model, directed = false) {
|
|
730
|
+
const n = model.nodeCount();
|
|
731
|
+
if (n === 0)
|
|
732
|
+
return model;
|
|
733
|
+
const nodes = model.nodes();
|
|
734
|
+
const orderedNodes = [nodes[0]];
|
|
735
|
+
const pickFlags = {};
|
|
736
|
+
pickFlags[nodes[0].id] = true;
|
|
737
|
+
let k = 0;
|
|
738
|
+
let i = 0;
|
|
739
|
+
model.forEachNode((node) => {
|
|
740
|
+
if (i !== 0) {
|
|
741
|
+
const currentDegree = model.degree(node.id, 'both');
|
|
742
|
+
const nextDegree = i < n - 1 ? model.degree(nodes[i + 1].id, 'both') : 0;
|
|
743
|
+
const currentNodeId = orderedNodes[k].id;
|
|
744
|
+
const isNeighbor = model
|
|
745
|
+
.neighbors(currentNodeId, 'both')
|
|
746
|
+
.includes(node.id);
|
|
747
|
+
if ((i === n - 1 || currentDegree !== nextDegree || isNeighbor) &&
|
|
748
|
+
!pickFlags[node.id]) {
|
|
749
|
+
orderedNodes.push(node);
|
|
750
|
+
pickFlags[node.id] = true;
|
|
751
|
+
k++;
|
|
787
752
|
}
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
753
|
+
else {
|
|
754
|
+
const children = directed
|
|
755
|
+
? model.successors(currentNodeId)
|
|
756
|
+
: model.neighbors(currentNodeId);
|
|
757
|
+
let foundChild = false;
|
|
758
|
+
for (let j = 0; j < children.length; j++) {
|
|
759
|
+
const childId = children[j];
|
|
760
|
+
const child = model.node(childId);
|
|
761
|
+
if (child &&
|
|
762
|
+
model.degree(childId) === model.degree(node.id) &&
|
|
763
|
+
!pickFlags[childId]) {
|
|
764
|
+
orderedNodes.push(child);
|
|
765
|
+
pickFlags[childId] = true;
|
|
766
|
+
foundChild = true;
|
|
767
|
+
break;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
let ii = 0;
|
|
771
|
+
while (!foundChild) {
|
|
772
|
+
if (!pickFlags[nodes[ii].id]) {
|
|
773
|
+
orderedNodes.push(nodes[ii]);
|
|
774
|
+
pickFlags[nodes[ii].id] = true;
|
|
775
|
+
foundChild = true;
|
|
776
|
+
}
|
|
777
|
+
ii++;
|
|
778
|
+
if (ii === n) {
|
|
779
|
+
break;
|
|
780
|
+
}
|
|
805
781
|
}
|
|
806
782
|
}
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
// Send Serialization Error To Caller
|
|
810
|
-
const [wireValue, transferables] = toWireValue({
|
|
811
|
-
value: new TypeError("Unserializable return value"),
|
|
812
|
-
[throwMarker]: 0,
|
|
813
|
-
});
|
|
814
|
-
ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);
|
|
815
|
-
});
|
|
783
|
+
}
|
|
784
|
+
i++;
|
|
816
785
|
});
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
786
|
+
// Update model with ordered nodes
|
|
787
|
+
model.setNodeOrder(orderedNodes);
|
|
788
|
+
return model;
|
|
820
789
|
}
|
|
821
|
-
|
|
822
|
-
|
|
790
|
+
|
|
791
|
+
function parsePoint(point) {
|
|
792
|
+
var _a;
|
|
793
|
+
return [point.x, point.y, (_a = point.z) !== null && _a !== void 0 ? _a : 0];
|
|
823
794
|
}
|
|
824
|
-
function
|
|
825
|
-
|
|
826
|
-
|
|
795
|
+
function toPointObject(point) {
|
|
796
|
+
var _a;
|
|
797
|
+
return { x: point[0], y: point[1], z: (_a = point[2]) !== null && _a !== void 0 ? _a : 0 };
|
|
827
798
|
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
}
|
|
839
|
-
try {
|
|
840
|
-
resolver(data);
|
|
841
|
-
}
|
|
842
|
-
finally {
|
|
843
|
-
pendingListeners.delete(data.id);
|
|
844
|
-
}
|
|
845
|
-
});
|
|
846
|
-
return createProxy(ep, pendingListeners, [], target);
|
|
799
|
+
|
|
800
|
+
function parseSize(size) {
|
|
801
|
+
if (!size)
|
|
802
|
+
return [0, 0, 0];
|
|
803
|
+
if (isNumber(size))
|
|
804
|
+
return [size, size, size];
|
|
805
|
+
else if (Array.isArray(size) && size.length === 0)
|
|
806
|
+
return [0, 0, 0];
|
|
807
|
+
const [x, y = x, z = x] = size;
|
|
808
|
+
return [x, y, z];
|
|
847
809
|
}
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
810
|
+
|
|
811
|
+
/**
|
|
812
|
+
* Viewport configuration such as width, height and center point.
|
|
813
|
+
*/
|
|
814
|
+
const normalizeViewport = (options) => {
|
|
815
|
+
const { width, height, center } = options;
|
|
816
|
+
const normalizedWidth = width !== null && width !== void 0 ? width : (typeof window !== 'undefined' ? window.innerWidth : 0);
|
|
817
|
+
const normalizedHeight = height !== null && height !== void 0 ? height : (typeof window !== 'undefined' ? window.innerHeight : 0);
|
|
818
|
+
const centerPoint = center !== null && center !== void 0 ? center : [normalizedWidth / 2, normalizedHeight / 2];
|
|
819
|
+
return {
|
|
820
|
+
width: normalizedWidth,
|
|
821
|
+
height: normalizedHeight,
|
|
822
|
+
center: centerPoint,
|
|
823
|
+
};
|
|
824
|
+
};
|
|
825
|
+
|
|
826
|
+
/**
|
|
827
|
+
* Format value with multiple types into a function that returns a number
|
|
828
|
+
* @param value The value to be formatted
|
|
829
|
+
* @param defaultValue The default value when value is invalid
|
|
830
|
+
* @returns A function that returns a number
|
|
831
|
+
*/
|
|
832
|
+
function formatNumberFn(value, defaultValue) {
|
|
833
|
+
// If value is a function, return it directly
|
|
834
|
+
if (isFunction(value)) {
|
|
835
|
+
return value;
|
|
836
|
+
}
|
|
837
|
+
// If value is a number, return a function that returns this number
|
|
838
|
+
if (isNumber(value)) {
|
|
839
|
+
return () => value;
|
|
851
840
|
}
|
|
841
|
+
// For other cases (undefined or invalid values), return default value function
|
|
842
|
+
return () => defaultValue;
|
|
852
843
|
}
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
844
|
+
/**
|
|
845
|
+
* Format size config with multiple types into a function that returns a size
|
|
846
|
+
* @param value The value to be formatted
|
|
847
|
+
* @param defaultValue The default value when value is invalid
|
|
848
|
+
* @param resultIsNumber Whether to return a number (max of width/height) or size array
|
|
849
|
+
* @returns A function that returns a size
|
|
850
|
+
*/
|
|
851
|
+
function formatSizeFn(value, defaultValue = 10) {
|
|
852
|
+
// If value is undefined, return default value function
|
|
853
|
+
if (!value) {
|
|
854
|
+
return () => defaultValue;
|
|
855
|
+
}
|
|
856
|
+
// If value is a function, return it directly
|
|
857
|
+
if (isFunction(value)) {
|
|
858
|
+
return value;
|
|
859
|
+
}
|
|
860
|
+
// If value is a number, return a function that returns this number
|
|
861
|
+
if (isNumber(value)) {
|
|
862
|
+
return () => value;
|
|
863
|
+
}
|
|
864
|
+
// If value is an array, return max or the array itself
|
|
865
|
+
if (Array.isArray(value)) {
|
|
866
|
+
return () => value;
|
|
867
|
+
}
|
|
868
|
+
// If value is an object with width and height
|
|
869
|
+
if (isObject$1(value) && value.width && value.height) {
|
|
870
|
+
return () => [value.width, value.height];
|
|
871
|
+
}
|
|
872
|
+
return () => defaultValue;
|
|
859
873
|
}
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
874
|
+
/**
|
|
875
|
+
* Format nodeSize and nodeSpacing into a function that returns the total size
|
|
876
|
+
* @param nodeSize The size of the node
|
|
877
|
+
* @param nodeSpacing The spacing around the node
|
|
878
|
+
* @param defaultNodeSize The default node size when value is invalid
|
|
879
|
+
* @returns A function that returns the total size (node size + spacing)
|
|
880
|
+
*/
|
|
881
|
+
const formatNodeSizeFn = (nodeSize, nodeSpacing, defaultNodeSize = 10) => {
|
|
882
|
+
const nodeSpacingFunc = formatNumberFn(nodeSpacing, 0);
|
|
883
|
+
const nodeSizeFunc = formatSizeFn(nodeSize, defaultNodeSize);
|
|
884
|
+
return (node) => {
|
|
885
|
+
const size = nodeSizeFunc(node);
|
|
886
|
+
const spacing = nodeSpacingFunc(node);
|
|
887
|
+
return Math.max(...parseSize(size)) + spacing;
|
|
888
|
+
};
|
|
889
|
+
};
|
|
890
|
+
|
|
891
|
+
class GraphLib {
|
|
892
|
+
constructor(data, options = {}) {
|
|
893
|
+
this.edgeIdCounter = new Map();
|
|
894
|
+
this.nodeMap = extractNodeData(data.nodes, options.node);
|
|
895
|
+
this.edgeMap = extractEdgeData(data.edges || [], options.edge, this.getEdgeId.bind(this));
|
|
896
|
+
}
|
|
897
|
+
data() {
|
|
898
|
+
return { nodes: this.nodeMap, edges: this.edgeMap };
|
|
899
|
+
}
|
|
900
|
+
replace(result) {
|
|
901
|
+
this.nodeMap = result.nodes;
|
|
902
|
+
this.edgeMap = result.edges;
|
|
903
|
+
this.clearCache();
|
|
904
|
+
}
|
|
905
|
+
nodes() {
|
|
906
|
+
return Array.from(this.nodeMap.values());
|
|
907
|
+
}
|
|
908
|
+
node(id) {
|
|
909
|
+
return this.nodeMap.get(id);
|
|
910
|
+
}
|
|
911
|
+
nodeAt(index) {
|
|
912
|
+
if (!this.indexNodeCache) {
|
|
913
|
+
this.buildNodeIndexCache();
|
|
914
|
+
}
|
|
915
|
+
const nodeId = this.indexNodeCache.get(index);
|
|
916
|
+
return nodeId ? this.nodeMap.get(nodeId) : undefined;
|
|
917
|
+
}
|
|
918
|
+
nodeIndexOf(id) {
|
|
919
|
+
var _a;
|
|
920
|
+
if (!this.nodeIndexCache) {
|
|
921
|
+
this.buildNodeIndexCache();
|
|
922
|
+
}
|
|
923
|
+
return (_a = this.nodeIndexCache.get(id)) !== null && _a !== void 0 ? _a : -1;
|
|
924
|
+
}
|
|
925
|
+
firstNode() {
|
|
926
|
+
return this.nodeMap.values().next().value;
|
|
927
|
+
}
|
|
928
|
+
forEachNode(callback) {
|
|
929
|
+
let i = 0;
|
|
930
|
+
this.nodeMap.forEach((node) => callback(node, i++));
|
|
931
|
+
}
|
|
932
|
+
originalNode(id) {
|
|
933
|
+
const node = this.nodeMap.get(id);
|
|
934
|
+
return node === null || node === void 0 ? void 0 : node._original;
|
|
935
|
+
}
|
|
936
|
+
nodeCount() {
|
|
937
|
+
return this.nodeMap.size;
|
|
938
|
+
}
|
|
939
|
+
edges() {
|
|
940
|
+
return Array.from(this.edgeMap.values());
|
|
941
|
+
}
|
|
942
|
+
edge(id) {
|
|
943
|
+
return this.edgeMap.get(id);
|
|
944
|
+
}
|
|
945
|
+
firstEdge() {
|
|
946
|
+
return this.edgeMap.values().next().value;
|
|
947
|
+
}
|
|
948
|
+
forEachEdge(callback) {
|
|
949
|
+
let i = 0;
|
|
950
|
+
this.edgeMap.forEach((edge) => callback(edge, i++));
|
|
951
|
+
}
|
|
952
|
+
originalEdge(id) {
|
|
953
|
+
const edge = this.edgeMap.get(id);
|
|
954
|
+
return edge === null || edge === void 0 ? void 0 : edge._original;
|
|
955
|
+
}
|
|
956
|
+
edgeCount() {
|
|
957
|
+
return this.edgeMap.size;
|
|
958
|
+
}
|
|
959
|
+
getEdgeId(edge) {
|
|
960
|
+
if (edge.id)
|
|
961
|
+
return edge.id;
|
|
962
|
+
const baseId = `${edge.source}-${edge.target}`;
|
|
963
|
+
const count = this.edgeIdCounter.get(baseId) || 0;
|
|
964
|
+
const id = count === 0 ? baseId : `${baseId}-${count}`;
|
|
965
|
+
this.edgeIdCounter.set(baseId, count + 1);
|
|
966
|
+
return id;
|
|
967
|
+
}
|
|
968
|
+
degree(nodeId, direction = 'both') {
|
|
969
|
+
if (!this.degreeCache) {
|
|
970
|
+
this.buildDegreeCache();
|
|
971
|
+
}
|
|
972
|
+
const degree = this.degreeCache.get(nodeId);
|
|
973
|
+
if (!degree)
|
|
974
|
+
return 0;
|
|
975
|
+
return degree[direction];
|
|
976
|
+
}
|
|
977
|
+
neighbors(nodeId, direction = 'both') {
|
|
978
|
+
if (!this.outAdjacencyCache || !this.inAdjacencyCache) {
|
|
979
|
+
this.buildAdjacencyCache();
|
|
867
980
|
}
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
981
|
+
if (direction === 'out') {
|
|
982
|
+
return Array.from(this.outAdjacencyCache.get(nodeId) || []);
|
|
983
|
+
}
|
|
984
|
+
if (direction === 'in') {
|
|
985
|
+
return Array.from(this.inAdjacencyCache.get(nodeId) || []);
|
|
986
|
+
}
|
|
987
|
+
if (this.bothAdjacencyCache) {
|
|
988
|
+
return Array.from(this.bothAdjacencyCache.get(nodeId) || []);
|
|
989
|
+
}
|
|
990
|
+
const inSet = this.inAdjacencyCache.get(nodeId);
|
|
991
|
+
const outSet = this.outAdjacencyCache.get(nodeId);
|
|
992
|
+
if (!inSet && !outSet)
|
|
993
|
+
return [];
|
|
994
|
+
if (!inSet)
|
|
995
|
+
return Array.from(outSet);
|
|
996
|
+
if (!outSet)
|
|
997
|
+
return Array.from(inSet);
|
|
998
|
+
const merged = new Set();
|
|
999
|
+
inSet.forEach((id) => merged.add(id));
|
|
1000
|
+
outSet.forEach((id) => merged.add(id));
|
|
1001
|
+
return Array.from(merged);
|
|
874
1002
|
}
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
if (proxyFinalizers) {
|
|
878
|
-
proxyFinalizers.unregister(proxy);
|
|
1003
|
+
successors(nodeId) {
|
|
1004
|
+
return this.neighbors(nodeId, 'out');
|
|
879
1005
|
}
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
1006
|
+
predecessors(nodeId) {
|
|
1007
|
+
return this.neighbors(nodeId, 'in');
|
|
1008
|
+
}
|
|
1009
|
+
setNodeOrder(nodes) {
|
|
1010
|
+
const next = new Map();
|
|
1011
|
+
for (const node of nodes)
|
|
1012
|
+
next.set(node.id, node);
|
|
1013
|
+
this.nodeMap = next;
|
|
1014
|
+
this.nodeIndexCache = undefined;
|
|
1015
|
+
this.indexNodeCache = undefined;
|
|
1016
|
+
}
|
|
1017
|
+
clearCache() {
|
|
1018
|
+
this.degreeCache = undefined;
|
|
1019
|
+
this.inAdjacencyCache = undefined;
|
|
1020
|
+
this.outAdjacencyCache = undefined;
|
|
1021
|
+
this.bothAdjacencyCache = undefined;
|
|
1022
|
+
this.nodeIndexCache = undefined;
|
|
1023
|
+
this.indexNodeCache = undefined;
|
|
1024
|
+
}
|
|
1025
|
+
buildDegreeCache() {
|
|
1026
|
+
this.degreeCache = new Map();
|
|
1027
|
+
for (const edge of this.edges()) {
|
|
1028
|
+
const { source, target } = edge;
|
|
1029
|
+
if (edge.source === edge.target)
|
|
1030
|
+
continue;
|
|
1031
|
+
if (!this.degreeCache.has(source)) {
|
|
1032
|
+
this.degreeCache.set(source, { in: 0, out: 0, both: 0 });
|
|
893
1033
|
}
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
const r = requestResponseMessage(ep, pendingListeners, {
|
|
899
|
-
type: "GET" /* MessageType.GET */,
|
|
900
|
-
path: path.map((p) => p.toString()),
|
|
901
|
-
}).then(fromWireValue);
|
|
902
|
-
return r.then.bind(r);
|
|
1034
|
+
const sourceDeg = this.degreeCache.get(edge.source);
|
|
1035
|
+
if (sourceDeg) {
|
|
1036
|
+
sourceDeg.out++;
|
|
1037
|
+
sourceDeg.both++;
|
|
903
1038
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
set(_target, prop, rawValue) {
|
|
907
|
-
throwIfProxyReleased(isProxyReleased);
|
|
908
|
-
// FIXME: ES6 Proxy Handler `set` methods are supposed to return a
|
|
909
|
-
// boolean. To show good will, we return true asynchronously ¯\_(ツ)_/¯
|
|
910
|
-
const [value, transferables] = toWireValue(rawValue);
|
|
911
|
-
return requestResponseMessage(ep, pendingListeners, {
|
|
912
|
-
type: "SET" /* MessageType.SET */,
|
|
913
|
-
path: [...path, prop].map((p) => p.toString()),
|
|
914
|
-
value,
|
|
915
|
-
}, transferables).then(fromWireValue);
|
|
916
|
-
},
|
|
917
|
-
apply(_target, _thisArg, rawArgumentList) {
|
|
918
|
-
throwIfProxyReleased(isProxyReleased);
|
|
919
|
-
const last = path[path.length - 1];
|
|
920
|
-
if (last === createEndpoint) {
|
|
921
|
-
return requestResponseMessage(ep, pendingListeners, {
|
|
922
|
-
type: "ENDPOINT" /* MessageType.ENDPOINT */,
|
|
923
|
-
}).then(fromWireValue);
|
|
1039
|
+
if (!this.degreeCache.has(target)) {
|
|
1040
|
+
this.degreeCache.set(target, { in: 0, out: 0, both: 0 });
|
|
924
1041
|
}
|
|
925
|
-
|
|
926
|
-
if (
|
|
927
|
-
|
|
1042
|
+
const targetDeg = this.degreeCache.get(edge.target);
|
|
1043
|
+
if (targetDeg) {
|
|
1044
|
+
targetDeg.in++;
|
|
1045
|
+
targetDeg.both++;
|
|
928
1046
|
}
|
|
929
|
-
const [argumentList, transferables] = processArguments(rawArgumentList);
|
|
930
|
-
return requestResponseMessage(ep, pendingListeners, {
|
|
931
|
-
type: "APPLY" /* MessageType.APPLY */,
|
|
932
|
-
path: path.map((p) => p.toString()),
|
|
933
|
-
argumentList,
|
|
934
|
-
}, transferables).then(fromWireValue);
|
|
935
|
-
},
|
|
936
|
-
construct(_target, rawArgumentList) {
|
|
937
|
-
throwIfProxyReleased(isProxyReleased);
|
|
938
|
-
const [argumentList, transferables] = processArguments(rawArgumentList);
|
|
939
|
-
return requestResponseMessage(ep, pendingListeners, {
|
|
940
|
-
type: "CONSTRUCT" /* MessageType.CONSTRUCT */,
|
|
941
|
-
path: path.map((p) => p.toString()),
|
|
942
|
-
argumentList,
|
|
943
|
-
}, transferables).then(fromWireValue);
|
|
944
|
-
},
|
|
945
|
-
});
|
|
946
|
-
registerProxy(proxy, ep);
|
|
947
|
-
return proxy;
|
|
948
|
-
}
|
|
949
|
-
function myFlat(arr) {
|
|
950
|
-
return Array.prototype.concat.apply([], arr);
|
|
951
|
-
}
|
|
952
|
-
function processArguments(argumentList) {
|
|
953
|
-
const processed = argumentList.map(toWireValue);
|
|
954
|
-
return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];
|
|
955
|
-
}
|
|
956
|
-
const transferCache = new WeakMap();
|
|
957
|
-
function transfer(obj, transfers) {
|
|
958
|
-
transferCache.set(obj, transfers);
|
|
959
|
-
return obj;
|
|
960
|
-
}
|
|
961
|
-
function proxy(obj) {
|
|
962
|
-
return Object.assign(obj, { [proxyMarker]: true });
|
|
963
|
-
}
|
|
964
|
-
function toWireValue(value) {
|
|
965
|
-
for (const [name, handler] of transferHandlers) {
|
|
966
|
-
if (handler.canHandle(value)) {
|
|
967
|
-
const [serializedValue, transferables] = handler.serialize(value);
|
|
968
|
-
return [
|
|
969
|
-
{
|
|
970
|
-
type: "HANDLER" /* WireValueType.HANDLER */,
|
|
971
|
-
name,
|
|
972
|
-
value: serializedValue,
|
|
973
|
-
},
|
|
974
|
-
transferables,
|
|
975
|
-
];
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
return [
|
|
979
|
-
{
|
|
980
|
-
type: "RAW" /* WireValueType.RAW */,
|
|
981
|
-
value,
|
|
982
|
-
},
|
|
983
|
-
transferCache.get(value) || [],
|
|
984
|
-
];
|
|
985
|
-
}
|
|
986
|
-
function fromWireValue(value) {
|
|
987
|
-
switch (value.type) {
|
|
988
|
-
case "HANDLER" /* WireValueType.HANDLER */:
|
|
989
|
-
return transferHandlers.get(value.name).deserialize(value.value);
|
|
990
|
-
case "RAW" /* WireValueType.RAW */:
|
|
991
|
-
return value.value;
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
function requestResponseMessage(ep, pendingListeners, msg, transfers) {
|
|
995
|
-
return new Promise((resolve) => {
|
|
996
|
-
const id = generateUUID();
|
|
997
|
-
pendingListeners.set(id, resolve);
|
|
998
|
-
if (ep.start) {
|
|
999
|
-
ep.start();
|
|
1000
1047
|
}
|
|
1001
|
-
ep.postMessage(Object.assign({ id }, msg), transfers);
|
|
1002
|
-
});
|
|
1003
|
-
}
|
|
1004
|
-
function generateUUID() {
|
|
1005
|
-
return new Array(4)
|
|
1006
|
-
.fill(0)
|
|
1007
|
-
.map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))
|
|
1008
|
-
.join("-");
|
|
1009
|
-
}
|
|
1010
|
-
|
|
1011
|
-
class Supervisor {
|
|
1012
|
-
constructor() {
|
|
1013
|
-
this.worker = null;
|
|
1014
|
-
this.workerApi = null;
|
|
1015
1048
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1049
|
+
buildAdjacencyCache() {
|
|
1050
|
+
this.inAdjacencyCache = new Map();
|
|
1051
|
+
this.outAdjacencyCache = new Map();
|
|
1052
|
+
for (const edge of this.edges()) {
|
|
1053
|
+
if (!this.nodeMap.has(edge.source) || !this.nodeMap.has(edge.target))
|
|
1054
|
+
continue;
|
|
1055
|
+
if (!this.outAdjacencyCache.has(edge.source)) {
|
|
1056
|
+
this.outAdjacencyCache.set(edge.source, new Set());
|
|
1023
1057
|
}
|
|
1024
|
-
|
|
1025
|
-
|
|
1058
|
+
this.outAdjacencyCache.get(edge.source).add(edge.target);
|
|
1059
|
+
if (!this.inAdjacencyCache.has(edge.target)) {
|
|
1060
|
+
this.inAdjacencyCache.set(edge.target, new Set());
|
|
1026
1061
|
}
|
|
1027
|
-
|
|
1028
|
-
});
|
|
1029
|
-
}
|
|
1030
|
-
/**
|
|
1031
|
-
* Destroy worker
|
|
1032
|
-
*/
|
|
1033
|
-
destroy() {
|
|
1034
|
-
if (this.workerApi) {
|
|
1035
|
-
this.workerApi.destroy();
|
|
1036
|
-
}
|
|
1037
|
-
if (this.worker) {
|
|
1038
|
-
this.worker.terminate();
|
|
1039
|
-
this.worker = null;
|
|
1040
|
-
this.workerApi = null;
|
|
1062
|
+
this.inAdjacencyCache.get(edge.target).add(edge.source);
|
|
1041
1063
|
}
|
|
1042
1064
|
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
this.worker = new Worker(workerPath, { type });
|
|
1052
|
-
this.workerApi = wrap(this.worker);
|
|
1065
|
+
buildNodeIndexCache() {
|
|
1066
|
+
this.nodeIndexCache = new Map();
|
|
1067
|
+
this.indexNodeCache = new Map();
|
|
1068
|
+
let index = 0;
|
|
1069
|
+
this.nodeMap.forEach((_node, nodeId) => {
|
|
1070
|
+
this.nodeIndexCache.set(nodeId, index);
|
|
1071
|
+
this.indexNodeCache.set(index, nodeId);
|
|
1072
|
+
index++;
|
|
1053
1073
|
});
|
|
1054
1074
|
}
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1075
|
+
destroy() {
|
|
1076
|
+
this.clearCache();
|
|
1077
|
+
this.nodeMap.clear();
|
|
1078
|
+
this.edgeMap.clear();
|
|
1079
|
+
this.edgeIdCounter.clear();
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
const nodeFields = [
|
|
1083
|
+
'id',
|
|
1084
|
+
'x',
|
|
1085
|
+
'y',
|
|
1086
|
+
'z',
|
|
1087
|
+
'vx',
|
|
1088
|
+
'vy',
|
|
1089
|
+
'vz',
|
|
1090
|
+
'fx',
|
|
1091
|
+
'fy',
|
|
1092
|
+
'fz',
|
|
1093
|
+
'parentId',
|
|
1094
|
+
];
|
|
1095
|
+
const edgeFields = ['id', 'source', 'target', 'points'];
|
|
1096
|
+
function extractNodeData(nodes, node) {
|
|
1097
|
+
if (!nodes) {
|
|
1098
|
+
throw new Error('Data.nodes is required');
|
|
1099
|
+
}
|
|
1100
|
+
const result = new Map();
|
|
1101
|
+
for (const datum of nodes) {
|
|
1102
|
+
const nodeData = { _original: datum };
|
|
1103
|
+
for (const field of nodeFields) {
|
|
1104
|
+
const value = datum[field];
|
|
1105
|
+
if (isNil(value))
|
|
1106
|
+
continue;
|
|
1107
|
+
nodeData[field] = value;
|
|
1067
1108
|
}
|
|
1068
|
-
if (
|
|
1069
|
-
const
|
|
1070
|
-
for (
|
|
1071
|
-
const
|
|
1072
|
-
if (
|
|
1073
|
-
|
|
1074
|
-
|
|
1109
|
+
if (node) {
|
|
1110
|
+
const customFields = node(datum);
|
|
1111
|
+
for (const key in customFields) {
|
|
1112
|
+
const value = customFields[key];
|
|
1113
|
+
if (isNil(value))
|
|
1114
|
+
continue;
|
|
1115
|
+
nodeData[key] = value;
|
|
1075
1116
|
}
|
|
1076
1117
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
const isArray = Array.isArray;
|
|
1082
|
-
|
|
1083
|
-
/**
|
|
1084
|
-
* Return the layout result for a graph with zero or one node.
|
|
1085
|
-
* @param graph original graph
|
|
1086
|
-
* @param center the layout center
|
|
1087
|
-
* @returns layout result
|
|
1088
|
-
*/
|
|
1089
|
-
function applySingleNodeLayout(model, center, dimensions = 2) {
|
|
1090
|
-
const n = model.nodeCount();
|
|
1091
|
-
if (n === 1) {
|
|
1092
|
-
const first = model.firstNode();
|
|
1093
|
-
first.x = center[0];
|
|
1094
|
-
first.y = center[1];
|
|
1095
|
-
if (dimensions === 3) {
|
|
1096
|
-
first.z = center[2] || 0;
|
|
1118
|
+
if (isNil(nodeData.id)) {
|
|
1119
|
+
throw new Error(`Node is missing id field`);
|
|
1097
1120
|
}
|
|
1121
|
+
result.set(nodeData.id, nodeData);
|
|
1098
1122
|
}
|
|
1123
|
+
return result;
|
|
1099
1124
|
}
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
const dist = Array.from({ length: n }, () => new Array(n));
|
|
1108
|
-
for (let i = 0; i < n; i++) {
|
|
1109
|
-
const row = adjMatrix[i];
|
|
1110
|
-
const drow = dist[i];
|
|
1111
|
-
for (let j = 0; j < n; j++) {
|
|
1112
|
-
drow[j] = i === j ? 0 : row[j] > 0 ? row[j] : Infinity;
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
// floyd
|
|
1116
|
-
for (let k = 0; k < n; k++) {
|
|
1117
|
-
const dk = dist[k];
|
|
1118
|
-
for (let i = 0; i < n; i++) {
|
|
1119
|
-
const di = dist[i];
|
|
1120
|
-
const dik = di[k];
|
|
1121
|
-
if (dik === Infinity)
|
|
1125
|
+
function extractEdgeData(edges, edge, getEdgeId) {
|
|
1126
|
+
const result = new Map();
|
|
1127
|
+
for (const datum of edges) {
|
|
1128
|
+
const edgeData = { _original: datum };
|
|
1129
|
+
for (const field of edgeFields) {
|
|
1130
|
+
const value = datum[field];
|
|
1131
|
+
if (isNil(value))
|
|
1122
1132
|
continue;
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1133
|
+
edgeData[field] = value;
|
|
1134
|
+
}
|
|
1135
|
+
if (edge) {
|
|
1136
|
+
const customFields = edge(datum);
|
|
1137
|
+
for (const key in customFields) {
|
|
1138
|
+
const value = customFields[key];
|
|
1139
|
+
if (isNil(value))
|
|
1126
1140
|
continue;
|
|
1127
|
-
|
|
1128
|
-
if (next < di[j]) {
|
|
1129
|
-
di[j] = next;
|
|
1130
|
-
}
|
|
1141
|
+
edgeData[key] = value;
|
|
1131
1142
|
}
|
|
1132
1143
|
}
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
};
|
|
1136
|
-
/**
|
|
1137
|
-
* Get the adjacency matrix of the graph model.
|
|
1138
|
-
*/
|
|
1139
|
-
const getAdjMatrix = (model, directed) => {
|
|
1140
|
-
const n = model.nodeCount();
|
|
1141
|
-
const matrix = Array.from({ length: n }, () => new Array(n));
|
|
1142
|
-
// map node with index in data.nodes
|
|
1143
|
-
const nodeMap = {};
|
|
1144
|
-
let i = 0;
|
|
1145
|
-
model.forEachNode((node) => {
|
|
1146
|
-
nodeMap[node.id] = i++;
|
|
1147
|
-
});
|
|
1148
|
-
model.forEachEdge((e) => {
|
|
1149
|
-
const sIndex = nodeMap[e.source];
|
|
1150
|
-
const tIndex = nodeMap[e.target];
|
|
1151
|
-
if (sIndex === undefined || tIndex === undefined)
|
|
1152
|
-
return;
|
|
1153
|
-
matrix[sIndex][tIndex] = 1;
|
|
1154
|
-
if (!directed) {
|
|
1155
|
-
matrix[tIndex][sIndex] = 1;
|
|
1144
|
+
if (isNil(edgeData.source) || isNil(edgeData.target)) {
|
|
1145
|
+
throw new Error(`Edge is missing source or target field`);
|
|
1156
1146
|
}
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
};
|
|
1160
|
-
/**
|
|
1161
|
-
* Get the adjacency list of the graph model.
|
|
1162
|
-
*/
|
|
1163
|
-
const getAdjList = (model, directed) => {
|
|
1164
|
-
const n = model.nodeCount();
|
|
1165
|
-
const adjList = Array.from({ length: n }, () => []);
|
|
1166
|
-
// map node with index
|
|
1167
|
-
const nodeMap = {};
|
|
1168
|
-
let idx = 0;
|
|
1169
|
-
model.forEachNode((node) => {
|
|
1170
|
-
nodeMap[node.id] = idx++;
|
|
1171
|
-
});
|
|
1172
|
-
model.forEachEdge((e) => {
|
|
1173
|
-
const s = nodeMap[e.source];
|
|
1174
|
-
const t = nodeMap[e.target];
|
|
1175
|
-
if (s == null || t == null)
|
|
1176
|
-
return;
|
|
1177
|
-
adjList[s].push(t);
|
|
1178
|
-
if (!directed)
|
|
1179
|
-
adjList[t].push(s);
|
|
1180
|
-
});
|
|
1181
|
-
return adjList;
|
|
1182
|
-
};
|
|
1183
|
-
/**
|
|
1184
|
-
* scale matrix
|
|
1185
|
-
* @param matrix [ [], [], [] ]
|
|
1186
|
-
* @param ratio
|
|
1187
|
-
*/
|
|
1188
|
-
const scaleMatrix = (matrix, ratio) => {
|
|
1189
|
-
const n = matrix.length;
|
|
1190
|
-
const result = new Array(n);
|
|
1191
|
-
for (let i = 0; i < n; i++) {
|
|
1192
|
-
const row = matrix[i];
|
|
1193
|
-
const m = row.length;
|
|
1194
|
-
const newRow = new Array(m);
|
|
1195
|
-
for (let j = 0; j < m; j++) {
|
|
1196
|
-
newRow[j] = row[j] * ratio;
|
|
1147
|
+
if (isNil(edgeData.id)) {
|
|
1148
|
+
edgeData.id = getEdgeId === null || getEdgeId === void 0 ? void 0 : getEdgeId(datum);
|
|
1197
1149
|
}
|
|
1198
|
-
result
|
|
1150
|
+
result.set(edgeData.id, edgeData);
|
|
1199
1151
|
}
|
|
1200
1152
|
return result;
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
*/
|
|
1207
|
-
const getLayoutBBox = (nodes) => {
|
|
1208
|
-
let minX = Infinity;
|
|
1209
|
-
let minY = Infinity;
|
|
1210
|
-
let maxX = -Infinity;
|
|
1211
|
-
let maxY = -Infinity;
|
|
1212
|
-
nodes.forEach((node) => {
|
|
1213
|
-
let size = node.data.size;
|
|
1214
|
-
if (isArray(size)) {
|
|
1215
|
-
if (size.length === 1)
|
|
1216
|
-
size = [size[0], size[0]];
|
|
1153
|
+
}
|
|
1154
|
+
function initNodePosition(model, width, height, dimensions = 2) {
|
|
1155
|
+
model.forEachNode((node) => {
|
|
1156
|
+
if (isNil(node.x)) {
|
|
1157
|
+
node.x = Math.random() * width;
|
|
1217
1158
|
}
|
|
1218
|
-
|
|
1219
|
-
|
|
1159
|
+
if (isNil(node.y)) {
|
|
1160
|
+
node.y = Math.random() * height;
|
|
1220
1161
|
}
|
|
1221
|
-
|
|
1222
|
-
|
|
1162
|
+
if (dimensions === 3 && isNil(node.z)) {
|
|
1163
|
+
node.z = Math.random() * Math.min(width, height);
|
|
1223
1164
|
}
|
|
1224
|
-
const halfSize = [size[0] / 2, size[1] / 2];
|
|
1225
|
-
const left = node.data.x - halfSize[0];
|
|
1226
|
-
const right = node.data.x + halfSize[0];
|
|
1227
|
-
const top = node.data.y - halfSize[1];
|
|
1228
|
-
const bottom = node.data.y + halfSize[1];
|
|
1229
|
-
if (minX > left)
|
|
1230
|
-
minX = left;
|
|
1231
|
-
if (minY > top)
|
|
1232
|
-
minY = top;
|
|
1233
|
-
if (maxX < right)
|
|
1234
|
-
maxX = right;
|
|
1235
|
-
if (maxY < bottom)
|
|
1236
|
-
maxY = bottom;
|
|
1237
1165
|
});
|
|
1238
|
-
|
|
1239
|
-
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
class RuntimeContext {
|
|
1169
|
+
constructor(data, options = {}) {
|
|
1170
|
+
this.graph = new GraphLib(data, options);
|
|
1171
|
+
}
|
|
1172
|
+
export() {
|
|
1173
|
+
return this.graph.data();
|
|
1174
|
+
}
|
|
1175
|
+
replace(result) {
|
|
1176
|
+
this.graph.replace(result);
|
|
1177
|
+
}
|
|
1178
|
+
forEachNode(callback) {
|
|
1179
|
+
this.graph.forEachNode(callback);
|
|
1180
|
+
}
|
|
1181
|
+
forEachEdge(callback) {
|
|
1182
|
+
this.graph.forEachEdge((edge, i) => {
|
|
1183
|
+
edge.sourceNode = this.graph.node(edge.source);
|
|
1184
|
+
edge.targetNode = this.graph.node(edge.target);
|
|
1185
|
+
callback(edge, i);
|
|
1186
|
+
});
|
|
1187
|
+
}
|
|
1188
|
+
destroy() {
|
|
1189
|
+
this.graph.destroy();
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1240
1193
|
/**
|
|
1241
|
-
*
|
|
1242
|
-
*
|
|
1243
|
-
*
|
|
1244
|
-
* @returns
|
|
1194
|
+
* @license
|
|
1195
|
+
* Copyright 2019 Google LLC
|
|
1196
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
1245
1197
|
*/
|
|
1246
|
-
const
|
|
1198
|
+
const proxyMarker = Symbol("Comlink.proxy");
|
|
1199
|
+
const createEndpoint = Symbol("Comlink.endpoint");
|
|
1200
|
+
const releaseProxy = Symbol("Comlink.releaseProxy");
|
|
1201
|
+
const finalizer = Symbol("Comlink.finalizer");
|
|
1202
|
+
const throwMarker = Symbol("Comlink.thrown");
|
|
1203
|
+
const isObject = (val) => (typeof val === "object" && val !== null) || typeof val === "function";
|
|
1247
1204
|
/**
|
|
1248
|
-
*
|
|
1249
|
-
* @param graphCore graphlib data structure
|
|
1250
|
-
* @param nodes begin nodes
|
|
1251
|
-
* @param fn will be called while visiting each node
|
|
1252
|
-
* @param mode 'TB' - visit from top to bottom; 'BT' - visit from bottom to top;
|
|
1253
|
-
* @returns
|
|
1205
|
+
* Internal transfer handle to handle objects marked to proxy.
|
|
1254
1206
|
*/
|
|
1255
|
-
const
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
return; // Stop all
|
|
1267
|
-
if (mode === 'TB')
|
|
1268
|
-
fn(node); // Traverse from top to bottom
|
|
1269
|
-
graphTreeDfs(graph, graph.getChildren(node.id, treeKey), fn, mode, treeKey, stopFns);
|
|
1270
|
-
if (mode !== 'TB')
|
|
1271
|
-
fn(node); // Traverse from bottom to top
|
|
1272
|
-
}
|
|
1207
|
+
const proxyTransferHandler = {
|
|
1208
|
+
canHandle: (val) => isObject(val) && val[proxyMarker],
|
|
1209
|
+
serialize(obj) {
|
|
1210
|
+
const { port1, port2 } = new MessageChannel();
|
|
1211
|
+
expose(obj, port1);
|
|
1212
|
+
return [port2, [port2]];
|
|
1213
|
+
},
|
|
1214
|
+
deserialize(port) {
|
|
1215
|
+
port.start();
|
|
1216
|
+
return wrap(port);
|
|
1217
|
+
},
|
|
1273
1218
|
};
|
|
1274
1219
|
/**
|
|
1275
|
-
*
|
|
1276
|
-
* Fully compatible with floydWarshall(adjMatrix).
|
|
1220
|
+
* Internal transfer handler to handle thrown exceptions.
|
|
1277
1221
|
*/
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1222
|
+
const throwTransferHandler = {
|
|
1223
|
+
canHandle: (value) => isObject(value) && throwMarker in value,
|
|
1224
|
+
serialize({ value }) {
|
|
1225
|
+
let serialized;
|
|
1226
|
+
if (value instanceof Error) {
|
|
1227
|
+
serialized = {
|
|
1228
|
+
isError: true,
|
|
1229
|
+
value: {
|
|
1230
|
+
message: value.message,
|
|
1231
|
+
name: value.name,
|
|
1232
|
+
stack: value.stack,
|
|
1233
|
+
},
|
|
1234
|
+
};
|
|
1235
|
+
}
|
|
1236
|
+
else {
|
|
1237
|
+
serialized = { isError: false, value };
|
|
1238
|
+
}
|
|
1239
|
+
return [serialized, []];
|
|
1240
|
+
},
|
|
1241
|
+
deserialize(serialized) {
|
|
1242
|
+
if (serialized.isError) {
|
|
1243
|
+
throw Object.assign(new Error(serialized.value.message), serialized.value);
|
|
1244
|
+
}
|
|
1245
|
+
throw serialized.value;
|
|
1246
|
+
},
|
|
1247
|
+
};
|
|
1293
1248
|
/**
|
|
1294
|
-
*
|
|
1249
|
+
* Allows customizing the serialization of certain values.
|
|
1295
1250
|
*/
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
const
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
if (
|
|
1306
|
-
|
|
1307
|
-
const neighbors = adjList[u];
|
|
1308
|
-
for (let i = 0; i < neighbors.length; i++) {
|
|
1309
|
-
const v = neighbors[i];
|
|
1310
|
-
const nd = d + 1;
|
|
1311
|
-
if (nd < dist[v]) {
|
|
1312
|
-
dist[v] = nd;
|
|
1313
|
-
heap.push([nd, v]);
|
|
1314
|
-
}
|
|
1251
|
+
const transferHandlers = new Map([
|
|
1252
|
+
["proxy", proxyTransferHandler],
|
|
1253
|
+
["throw", throwTransferHandler],
|
|
1254
|
+
]);
|
|
1255
|
+
function isAllowedOrigin(allowedOrigins, origin) {
|
|
1256
|
+
for (const allowedOrigin of allowedOrigins) {
|
|
1257
|
+
if (origin === allowedOrigin || allowedOrigin === "*") {
|
|
1258
|
+
return true;
|
|
1259
|
+
}
|
|
1260
|
+
if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {
|
|
1261
|
+
return true;
|
|
1315
1262
|
}
|
|
1316
1263
|
}
|
|
1317
|
-
return
|
|
1264
|
+
return false;
|
|
1318
1265
|
}
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
push(item) {
|
|
1324
|
-
this.data.push(item);
|
|
1325
|
-
this.bubbleUp(this.data.length - 1);
|
|
1326
|
-
}
|
|
1327
|
-
pop() {
|
|
1328
|
-
const top = this.data[0];
|
|
1329
|
-
const end = this.data.pop();
|
|
1330
|
-
if (this.data.length > 0) {
|
|
1331
|
-
this.data[0] = end;
|
|
1332
|
-
this.bubbleDown(0);
|
|
1266
|
+
function expose(obj, ep = globalThis, allowedOrigins = ["*"]) {
|
|
1267
|
+
ep.addEventListener("message", function callback(ev) {
|
|
1268
|
+
if (!ev || !ev.data) {
|
|
1269
|
+
return;
|
|
1333
1270
|
}
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
return this.data.length === 0;
|
|
1338
|
-
}
|
|
1339
|
-
bubbleUp(pos) {
|
|
1340
|
-
const data = this.data;
|
|
1341
|
-
while (pos > 0) {
|
|
1342
|
-
const parent = (pos - 1) >> 1;
|
|
1343
|
-
if (data[parent][0] <= data[pos][0])
|
|
1344
|
-
break;
|
|
1345
|
-
[data[parent], data[pos]] = [data[pos], data[parent]];
|
|
1346
|
-
pos = parent;
|
|
1271
|
+
if (!isAllowedOrigin(allowedOrigins, ev.origin)) {
|
|
1272
|
+
console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);
|
|
1273
|
+
return;
|
|
1347
1274
|
}
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
const
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1275
|
+
const { id, type, path } = Object.assign({ path: [] }, ev.data);
|
|
1276
|
+
const argumentList = (ev.data.argumentList || []).map(fromWireValue);
|
|
1277
|
+
let returnValue;
|
|
1278
|
+
try {
|
|
1279
|
+
const parent = path.slice(0, -1).reduce((obj, prop) => obj[prop], obj);
|
|
1280
|
+
const rawValue = path.reduce((obj, prop) => obj[prop], obj);
|
|
1281
|
+
switch (type) {
|
|
1282
|
+
case "GET" /* MessageType.GET */:
|
|
1283
|
+
{
|
|
1284
|
+
returnValue = rawValue;
|
|
1285
|
+
}
|
|
1286
|
+
break;
|
|
1287
|
+
case "SET" /* MessageType.SET */:
|
|
1288
|
+
{
|
|
1289
|
+
parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);
|
|
1290
|
+
returnValue = true;
|
|
1291
|
+
}
|
|
1292
|
+
break;
|
|
1293
|
+
case "APPLY" /* MessageType.APPLY */:
|
|
1294
|
+
{
|
|
1295
|
+
returnValue = rawValue.apply(parent, argumentList);
|
|
1296
|
+
}
|
|
1297
|
+
break;
|
|
1298
|
+
case "CONSTRUCT" /* MessageType.CONSTRUCT */:
|
|
1299
|
+
{
|
|
1300
|
+
const value = new rawValue(...argumentList);
|
|
1301
|
+
returnValue = proxy(value);
|
|
1302
|
+
}
|
|
1303
|
+
break;
|
|
1304
|
+
case "ENDPOINT" /* MessageType.ENDPOINT */:
|
|
1305
|
+
{
|
|
1306
|
+
const { port1, port2 } = new MessageChannel();
|
|
1307
|
+
expose(obj, port2);
|
|
1308
|
+
returnValue = transfer(port1, [port1]);
|
|
1309
|
+
}
|
|
1310
|
+
break;
|
|
1311
|
+
case "RELEASE" /* MessageType.RELEASE */:
|
|
1312
|
+
{
|
|
1313
|
+
returnValue = undefined;
|
|
1314
|
+
}
|
|
1315
|
+
break;
|
|
1316
|
+
default:
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
catch (value) {
|
|
1321
|
+
returnValue = { value, [throwMarker]: 0 };
|
|
1364
1322
|
}
|
|
1323
|
+
Promise.resolve(returnValue)
|
|
1324
|
+
.catch((value) => {
|
|
1325
|
+
return { value, [throwMarker]: 0 };
|
|
1326
|
+
})
|
|
1327
|
+
.then((returnValue) => {
|
|
1328
|
+
const [wireValue, transferables] = toWireValue(returnValue);
|
|
1329
|
+
ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);
|
|
1330
|
+
if (type === "RELEASE" /* MessageType.RELEASE */) {
|
|
1331
|
+
// detach and deactive after sending release response above.
|
|
1332
|
+
ep.removeEventListener("message", callback);
|
|
1333
|
+
closeEndPoint(ep);
|
|
1334
|
+
if (finalizer in obj && typeof obj[finalizer] === "function") {
|
|
1335
|
+
obj[finalizer]();
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
})
|
|
1339
|
+
.catch((error) => {
|
|
1340
|
+
// Send Serialization Error To Caller
|
|
1341
|
+
const [wireValue, transferables] = toWireValue({
|
|
1342
|
+
value: new TypeError("Unserializable return value"),
|
|
1343
|
+
[throwMarker]: 0,
|
|
1344
|
+
});
|
|
1345
|
+
ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);
|
|
1346
|
+
});
|
|
1347
|
+
});
|
|
1348
|
+
if (ep.start) {
|
|
1349
|
+
ep.start();
|
|
1365
1350
|
}
|
|
1366
1351
|
}
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
* Get nested property value
|
|
1370
|
-
* For example: getNestedValue(obj, 'a.b.c') will return obj.a.b.c
|
|
1371
|
-
*/
|
|
1372
|
-
function getNestedValue(obj, path) {
|
|
1373
|
-
const keys = String(path).split('.');
|
|
1374
|
-
return get$1(obj, keys);
|
|
1352
|
+
function isMessagePort(endpoint) {
|
|
1353
|
+
return endpoint.constructor.name === "MessagePort";
|
|
1375
1354
|
}
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
*/
|
|
1380
|
-
function setNestedValue(obj, path, value) {
|
|
1381
|
-
const keys = String(path).split('.');
|
|
1382
|
-
set$1(obj, keys, value);
|
|
1355
|
+
function closeEndPoint(endpoint) {
|
|
1356
|
+
if (isMessagePort(endpoint))
|
|
1357
|
+
endpoint.close();
|
|
1383
1358
|
}
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
target[key] = value;
|
|
1401
|
-
}
|
|
1402
|
-
});
|
|
1359
|
+
function wrap(ep, target) {
|
|
1360
|
+
const pendingListeners = new Map();
|
|
1361
|
+
ep.addEventListener("message", function handleMessage(ev) {
|
|
1362
|
+
const { data } = ev;
|
|
1363
|
+
if (!data || !data.id) {
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
const resolver = pendingListeners.get(data.id);
|
|
1367
|
+
if (!resolver) {
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
try {
|
|
1371
|
+
resolver(data);
|
|
1372
|
+
}
|
|
1373
|
+
finally {
|
|
1374
|
+
pendingListeners.delete(data.id);
|
|
1403
1375
|
}
|
|
1404
1376
|
});
|
|
1405
|
-
return target;
|
|
1406
|
-
}
|
|
1407
|
-
function mergeOptions(base, patch) {
|
|
1408
|
-
return Object.assign({}, base, patch || {});
|
|
1377
|
+
return createProxy(ep, pendingListeners, [], target);
|
|
1409
1378
|
}
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
function sort$1(model, compareFn) {
|
|
1415
|
-
const nodes = model.nodes();
|
|
1416
|
-
nodes.sort(compareFn);
|
|
1417
|
-
model.setNodeOrder(nodes);
|
|
1418
|
-
return model;
|
|
1379
|
+
function throwIfProxyReleased(isReleased) {
|
|
1380
|
+
if (isReleased) {
|
|
1381
|
+
throw new Error("Proxy has been released and is not useable");
|
|
1382
|
+
}
|
|
1419
1383
|
}
|
|
1420
|
-
function
|
|
1421
|
-
return
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1384
|
+
function releaseEndpoint(ep) {
|
|
1385
|
+
return requestResponseMessage(ep, new Map(), {
|
|
1386
|
+
type: "RELEASE" /* MessageType.RELEASE */,
|
|
1387
|
+
}).then(() => {
|
|
1388
|
+
closeEndPoint(ep);
|
|
1425
1389
|
});
|
|
1426
1390
|
}
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
if (typeof idA === 'number' && typeof idB === 'number') {
|
|
1435
|
-
return idA - idB;
|
|
1391
|
+
const proxyCounter = new WeakMap();
|
|
1392
|
+
const proxyFinalizers = "FinalizationRegistry" in globalThis &&
|
|
1393
|
+
new FinalizationRegistry((ep) => {
|
|
1394
|
+
const newCount = (proxyCounter.get(ep) || 0) - 1;
|
|
1395
|
+
proxyCounter.set(ep, newCount);
|
|
1396
|
+
if (newCount === 0) {
|
|
1397
|
+
releaseEndpoint(ep);
|
|
1436
1398
|
}
|
|
1437
|
-
return String(idA).localeCompare(String(idB));
|
|
1438
1399
|
});
|
|
1400
|
+
function registerProxy(proxy, ep) {
|
|
1401
|
+
const newCount = (proxyCounter.get(ep) || 0) + 1;
|
|
1402
|
+
proxyCounter.set(ep, newCount);
|
|
1403
|
+
if (proxyFinalizers) {
|
|
1404
|
+
proxyFinalizers.register(proxy, ep, proxy);
|
|
1405
|
+
}
|
|
1439
1406
|
}
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
return sort$1(model, (nodeA, nodeB) => {
|
|
1445
|
-
const a = model.originalNode(nodeA.id);
|
|
1446
|
-
const b = model.originalNode(nodeB.id);
|
|
1447
|
-
return sorter(a, b);
|
|
1448
|
-
});
|
|
1407
|
+
function unregisterProxy(proxy) {
|
|
1408
|
+
if (proxyFinalizers) {
|
|
1409
|
+
proxyFinalizers.unregister(proxy);
|
|
1410
|
+
}
|
|
1449
1411
|
}
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
let i = 0;
|
|
1463
|
-
model.forEachNode((node) => {
|
|
1464
|
-
if (i !== 0) {
|
|
1465
|
-
const currentDegree = model.degree(node.id, 'both');
|
|
1466
|
-
const nextDegree = i < n - 1 ? model.degree(nodes[i + 1].id, 'both') : 0;
|
|
1467
|
-
const currentNodeId = orderedNodes[k].id;
|
|
1468
|
-
const isNeighbor = model
|
|
1469
|
-
.neighbors(currentNodeId, 'both')
|
|
1470
|
-
.includes(node.id);
|
|
1471
|
-
if ((i === n - 1 || currentDegree !== nextDegree || isNeighbor) &&
|
|
1472
|
-
!pickFlags[node.id]) {
|
|
1473
|
-
orderedNodes.push(node);
|
|
1474
|
-
pickFlags[node.id] = true;
|
|
1475
|
-
k++;
|
|
1412
|
+
function createProxy(ep, pendingListeners, path = [], target = function () { }) {
|
|
1413
|
+
let isProxyReleased = false;
|
|
1414
|
+
const proxy = new Proxy(target, {
|
|
1415
|
+
get(_target, prop) {
|
|
1416
|
+
throwIfProxyReleased(isProxyReleased);
|
|
1417
|
+
if (prop === releaseProxy) {
|
|
1418
|
+
return () => {
|
|
1419
|
+
unregisterProxy(proxy);
|
|
1420
|
+
releaseEndpoint(ep);
|
|
1421
|
+
pendingListeners.clear();
|
|
1422
|
+
isProxyReleased = true;
|
|
1423
|
+
};
|
|
1476
1424
|
}
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
: model.neighbors(currentNodeId);
|
|
1481
|
-
let foundChild = false;
|
|
1482
|
-
for (let j = 0; j < children.length; j++) {
|
|
1483
|
-
const childId = children[j];
|
|
1484
|
-
const child = model.node(childId);
|
|
1485
|
-
if (child &&
|
|
1486
|
-
model.degree(childId) === model.degree(node.id) &&
|
|
1487
|
-
!pickFlags[childId]) {
|
|
1488
|
-
orderedNodes.push(child);
|
|
1489
|
-
pickFlags[childId] = true;
|
|
1490
|
-
foundChild = true;
|
|
1491
|
-
break;
|
|
1492
|
-
}
|
|
1493
|
-
}
|
|
1494
|
-
let ii = 0;
|
|
1495
|
-
while (!foundChild) {
|
|
1496
|
-
if (!pickFlags[nodes[ii].id]) {
|
|
1497
|
-
orderedNodes.push(nodes[ii]);
|
|
1498
|
-
pickFlags[nodes[ii].id] = true;
|
|
1499
|
-
foundChild = true;
|
|
1500
|
-
}
|
|
1501
|
-
ii++;
|
|
1502
|
-
if (ii === n) {
|
|
1503
|
-
break;
|
|
1504
|
-
}
|
|
1425
|
+
if (prop === "then") {
|
|
1426
|
+
if (path.length === 0) {
|
|
1427
|
+
return { then: () => proxy };
|
|
1505
1428
|
}
|
|
1429
|
+
const r = requestResponseMessage(ep, pendingListeners, {
|
|
1430
|
+
type: "GET" /* MessageType.GET */,
|
|
1431
|
+
path: path.map((p) => p.toString()),
|
|
1432
|
+
}).then(fromWireValue);
|
|
1433
|
+
return r.then.bind(r);
|
|
1434
|
+
}
|
|
1435
|
+
return createProxy(ep, pendingListeners, [...path, prop]);
|
|
1436
|
+
},
|
|
1437
|
+
set(_target, prop, rawValue) {
|
|
1438
|
+
throwIfProxyReleased(isProxyReleased);
|
|
1439
|
+
// FIXME: ES6 Proxy Handler `set` methods are supposed to return a
|
|
1440
|
+
// boolean. To show good will, we return true asynchronously ¯\_(ツ)_/¯
|
|
1441
|
+
const [value, transferables] = toWireValue(rawValue);
|
|
1442
|
+
return requestResponseMessage(ep, pendingListeners, {
|
|
1443
|
+
type: "SET" /* MessageType.SET */,
|
|
1444
|
+
path: [...path, prop].map((p) => p.toString()),
|
|
1445
|
+
value,
|
|
1446
|
+
}, transferables).then(fromWireValue);
|
|
1447
|
+
},
|
|
1448
|
+
apply(_target, _thisArg, rawArgumentList) {
|
|
1449
|
+
throwIfProxyReleased(isProxyReleased);
|
|
1450
|
+
const last = path[path.length - 1];
|
|
1451
|
+
if (last === createEndpoint) {
|
|
1452
|
+
return requestResponseMessage(ep, pendingListeners, {
|
|
1453
|
+
type: "ENDPOINT" /* MessageType.ENDPOINT */,
|
|
1454
|
+
}).then(fromWireValue);
|
|
1455
|
+
}
|
|
1456
|
+
// We just pretend that `bind()` didn’t happen.
|
|
1457
|
+
if (last === "bind") {
|
|
1458
|
+
return createProxy(ep, pendingListeners, path.slice(0, -1));
|
|
1506
1459
|
}
|
|
1460
|
+
const [argumentList, transferables] = processArguments(rawArgumentList);
|
|
1461
|
+
return requestResponseMessage(ep, pendingListeners, {
|
|
1462
|
+
type: "APPLY" /* MessageType.APPLY */,
|
|
1463
|
+
path: path.map((p) => p.toString()),
|
|
1464
|
+
argumentList,
|
|
1465
|
+
}, transferables).then(fromWireValue);
|
|
1466
|
+
},
|
|
1467
|
+
construct(_target, rawArgumentList) {
|
|
1468
|
+
throwIfProxyReleased(isProxyReleased);
|
|
1469
|
+
const [argumentList, transferables] = processArguments(rawArgumentList);
|
|
1470
|
+
return requestResponseMessage(ep, pendingListeners, {
|
|
1471
|
+
type: "CONSTRUCT" /* MessageType.CONSTRUCT */,
|
|
1472
|
+
path: path.map((p) => p.toString()),
|
|
1473
|
+
argumentList,
|
|
1474
|
+
}, transferables).then(fromWireValue);
|
|
1475
|
+
},
|
|
1476
|
+
});
|
|
1477
|
+
registerProxy(proxy, ep);
|
|
1478
|
+
return proxy;
|
|
1479
|
+
}
|
|
1480
|
+
function myFlat(arr) {
|
|
1481
|
+
return Array.prototype.concat.apply([], arr);
|
|
1482
|
+
}
|
|
1483
|
+
function processArguments(argumentList) {
|
|
1484
|
+
const processed = argumentList.map(toWireValue);
|
|
1485
|
+
return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];
|
|
1486
|
+
}
|
|
1487
|
+
const transferCache = new WeakMap();
|
|
1488
|
+
function transfer(obj, transfers) {
|
|
1489
|
+
transferCache.set(obj, transfers);
|
|
1490
|
+
return obj;
|
|
1491
|
+
}
|
|
1492
|
+
function proxy(obj) {
|
|
1493
|
+
return Object.assign(obj, { [proxyMarker]: true });
|
|
1494
|
+
}
|
|
1495
|
+
function toWireValue(value) {
|
|
1496
|
+
for (const [name, handler] of transferHandlers) {
|
|
1497
|
+
if (handler.canHandle(value)) {
|
|
1498
|
+
const [serializedValue, transferables] = handler.serialize(value);
|
|
1499
|
+
return [
|
|
1500
|
+
{
|
|
1501
|
+
type: "HANDLER" /* WireValueType.HANDLER */,
|
|
1502
|
+
name,
|
|
1503
|
+
value: serializedValue,
|
|
1504
|
+
},
|
|
1505
|
+
transferables,
|
|
1506
|
+
];
|
|
1507
1507
|
}
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1508
|
+
}
|
|
1509
|
+
return [
|
|
1510
|
+
{
|
|
1511
|
+
type: "RAW" /* WireValueType.RAW */,
|
|
1512
|
+
value,
|
|
1513
|
+
},
|
|
1514
|
+
transferCache.get(value) || [],
|
|
1515
|
+
];
|
|
1513
1516
|
}
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1517
|
+
function fromWireValue(value) {
|
|
1518
|
+
switch (value.type) {
|
|
1519
|
+
case "HANDLER" /* WireValueType.HANDLER */:
|
|
1520
|
+
return transferHandlers.get(value.name).deserialize(value.value);
|
|
1521
|
+
case "RAW" /* WireValueType.RAW */:
|
|
1522
|
+
return value.value;
|
|
1523
|
+
}
|
|
1518
1524
|
}
|
|
1519
|
-
function
|
|
1520
|
-
|
|
1521
|
-
|
|
1525
|
+
function requestResponseMessage(ep, pendingListeners, msg, transfers) {
|
|
1526
|
+
return new Promise((resolve) => {
|
|
1527
|
+
const id = generateUUID();
|
|
1528
|
+
pendingListeners.set(id, resolve);
|
|
1529
|
+
if (ep.start) {
|
|
1530
|
+
ep.start();
|
|
1531
|
+
}
|
|
1532
|
+
ep.postMessage(Object.assign({ id }, msg), transfers);
|
|
1533
|
+
});
|
|
1522
1534
|
}
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
return [size, size, size];
|
|
1529
|
-
else if (Array.isArray(size) && size.length === 0)
|
|
1530
|
-
return [0, 0, 0];
|
|
1531
|
-
const [x, y = x, z = x] = size;
|
|
1532
|
-
return [x, y, z];
|
|
1535
|
+
function generateUUID() {
|
|
1536
|
+
return new Array(4)
|
|
1537
|
+
.fill(0)
|
|
1538
|
+
.map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16))
|
|
1539
|
+
.join("-");
|
|
1533
1540
|
}
|
|
1534
1541
|
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1542
|
+
class Supervisor {
|
|
1543
|
+
constructor() {
|
|
1544
|
+
this.worker = null;
|
|
1545
|
+
this.workerApi = null;
|
|
1546
|
+
}
|
|
1547
|
+
/**
|
|
1548
|
+
* Execute layout in worker
|
|
1549
|
+
*/
|
|
1550
|
+
execute(layoutId, data, options) {
|
|
1551
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1552
|
+
if (!this.worker) {
|
|
1553
|
+
yield this.initWorker();
|
|
1554
|
+
}
|
|
1555
|
+
if (!this.workerApi) {
|
|
1556
|
+
throw new Error('Worker API not initialized');
|
|
1557
|
+
}
|
|
1558
|
+
return yield this.workerApi.execute(layoutId, data, options);
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1561
|
+
/**
|
|
1562
|
+
* Destroy worker
|
|
1563
|
+
*/
|
|
1564
|
+
destroy() {
|
|
1565
|
+
if (this.workerApi) {
|
|
1566
|
+
this.workerApi.destroy();
|
|
1567
|
+
}
|
|
1568
|
+
if (this.worker) {
|
|
1569
|
+
this.worker.terminate();
|
|
1570
|
+
this.worker = null;
|
|
1571
|
+
this.workerApi = null;
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
/**
|
|
1575
|
+
* Initialize worker
|
|
1576
|
+
*/
|
|
1577
|
+
initWorker() {
|
|
1578
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1579
|
+
const workerPath = this.resolveWorkerPath();
|
|
1580
|
+
const isESM = workerPath.includes('/lib/') || workerPath.endsWith('.mjs');
|
|
1581
|
+
const type = isESM ? 'module' : 'classic';
|
|
1582
|
+
this.worker = new Worker(workerPath, { type });
|
|
1583
|
+
this.workerApi = wrap(this.worker);
|
|
1584
|
+
});
|
|
1585
|
+
}
|
|
1586
|
+
/**
|
|
1587
|
+
* Resolve worker script path which works in both ESM and UMD environments
|
|
1588
|
+
*/
|
|
1589
|
+
resolveWorkerPath() {
|
|
1590
|
+
if (typeof ({ url: (typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)) }) !== 'undefined' && (typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href))) {
|
|
1591
|
+
const currentUrl = new URL((typeof document === 'undefined' && typeof location === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : typeof document === 'undefined' ? location.href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href)));
|
|
1592
|
+
// e.g. `.../lib/runtime/supervisor.js` -> `.../lib/worker.js`
|
|
1593
|
+
const asRoot = currentUrl.href.replace(/\/runtime\/[^/]+\.js$/, '/worker.js');
|
|
1594
|
+
if (asRoot !== currentUrl.href)
|
|
1595
|
+
return asRoot;
|
|
1596
|
+
// Fallback: keep legacy behavior (same directory)
|
|
1597
|
+
return currentUrl.href.replace(/\/[^/]+\.js$/, '/worker.js');
|
|
1598
|
+
}
|
|
1599
|
+
if (typeof document !== 'undefined') {
|
|
1600
|
+
const scripts = document.getElementsByTagName('script');
|
|
1601
|
+
for (let i = scripts.length - 1; i >= 0; i--) {
|
|
1602
|
+
const src = scripts[i].src;
|
|
1603
|
+
if (src && (src.includes('index.js') || src.includes('index.min.js'))) {
|
|
1604
|
+
return src.replace(/index(\.min)?\.js/, 'worker.js');
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
return './worker.js';
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1549
1611
|
|
|
1550
1612
|
/**
|
|
1551
1613
|
* <zh/> 布局基类
|
|
@@ -1555,14 +1617,17 @@
|
|
|
1555
1617
|
class BaseLayout {
|
|
1556
1618
|
constructor(options) {
|
|
1557
1619
|
this.supervisor = null;
|
|
1558
|
-
this.initialOptions = mergeOptions(this.getDefaultOptions(), options);
|
|
1620
|
+
this.initialOptions = this.mergeOptions(this.getDefaultOptions(), options);
|
|
1559
1621
|
}
|
|
1560
1622
|
get options() {
|
|
1561
1623
|
return this.runtimeOptions || this.initialOptions;
|
|
1562
1624
|
}
|
|
1625
|
+
mergeOptions(base, patch) {
|
|
1626
|
+
return Object.assign({}, base, patch || {});
|
|
1627
|
+
}
|
|
1563
1628
|
execute(data, userOptions) {
|
|
1564
1629
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1565
|
-
this.runtimeOptions = mergeOptions(this.initialOptions, userOptions);
|
|
1630
|
+
this.runtimeOptions = this.mergeOptions(this.initialOptions, userOptions);
|
|
1566
1631
|
const { node, edge, enableWorker } = this.runtimeOptions;
|
|
1567
1632
|
this.context = new RuntimeContext(data, { node, edge });
|
|
1568
1633
|
this.model = this.context.graph;
|
|
@@ -1627,71 +1692,6 @@
|
|
|
1627
1692
|
return !!layout.tick && !!layout.stop;
|
|
1628
1693
|
}
|
|
1629
1694
|
|
|
1630
|
-
/**
|
|
1631
|
-
* Format value with multiple types into a function that returns a number
|
|
1632
|
-
* @param value The value to be formatted
|
|
1633
|
-
* @param defaultValue The default value when value is invalid
|
|
1634
|
-
* @returns A function that returns a number
|
|
1635
|
-
*/
|
|
1636
|
-
function formatNumberFn(value, defaultValue) {
|
|
1637
|
-
// If value is a function, return it directly
|
|
1638
|
-
if (isFunction(value)) {
|
|
1639
|
-
return value;
|
|
1640
|
-
}
|
|
1641
|
-
// If value is a number, return a function that returns this number
|
|
1642
|
-
if (isNumber(value)) {
|
|
1643
|
-
return () => value;
|
|
1644
|
-
}
|
|
1645
|
-
// For other cases (undefined or invalid values), return default value function
|
|
1646
|
-
return () => defaultValue;
|
|
1647
|
-
}
|
|
1648
|
-
/**
|
|
1649
|
-
* Format size config with multiple types into a function that returns a size
|
|
1650
|
-
* @param value The value to be formatted
|
|
1651
|
-
* @param defaultValue The default value when value is invalid
|
|
1652
|
-
* @param resultIsNumber Whether to return a number (max of width/height) or size array
|
|
1653
|
-
* @returns A function that returns a size
|
|
1654
|
-
*/
|
|
1655
|
-
function formatSizeFn(value, defaultValue = 10) {
|
|
1656
|
-
// If value is undefined, return default value function
|
|
1657
|
-
if (!value) {
|
|
1658
|
-
return () => defaultValue;
|
|
1659
|
-
}
|
|
1660
|
-
// If value is a function, return it directly
|
|
1661
|
-
if (isFunction(value)) {
|
|
1662
|
-
return value;
|
|
1663
|
-
}
|
|
1664
|
-
// If value is a number, return a function that returns this number
|
|
1665
|
-
if (isNumber(value)) {
|
|
1666
|
-
return () => value;
|
|
1667
|
-
}
|
|
1668
|
-
// If value is an array, return max or the array itself
|
|
1669
|
-
if (Array.isArray(value)) {
|
|
1670
|
-
return () => value;
|
|
1671
|
-
}
|
|
1672
|
-
// If value is an object with width and height
|
|
1673
|
-
if (isObject$1(value) && value.width && value.height) {
|
|
1674
|
-
return () => [value.width, value.height];
|
|
1675
|
-
}
|
|
1676
|
-
return () => defaultValue;
|
|
1677
|
-
}
|
|
1678
|
-
/**
|
|
1679
|
-
* Format nodeSize and nodeSpacing into a function that returns the total size
|
|
1680
|
-
* @param nodeSize The size of the node
|
|
1681
|
-
* @param nodeSpacing The spacing around the node
|
|
1682
|
-
* @param defaultNodeSize The default node size when value is invalid
|
|
1683
|
-
* @returns A function that returns the total size (node size + spacing)
|
|
1684
|
-
*/
|
|
1685
|
-
const formatNodeSizeFn = (nodeSize, nodeSpacing, defaultNodeSize = 10) => {
|
|
1686
|
-
const nodeSpacingFunc = formatNumberFn(nodeSpacing, 0);
|
|
1687
|
-
const nodeSizeFunc = formatSizeFn(nodeSize, defaultNodeSize);
|
|
1688
|
-
return (node) => {
|
|
1689
|
-
const size = nodeSizeFunc(node);
|
|
1690
|
-
const spacing = nodeSpacingFunc(node);
|
|
1691
|
-
return Math.max(...parseSize(size)) + spacing;
|
|
1692
|
-
};
|
|
1693
|
-
};
|
|
1694
|
-
|
|
1695
1695
|
/**
|
|
1696
1696
|
* <zh/> 内部图数据结构,用于 antv-dagre 布局算法
|
|
1697
1697
|
*
|
|
@@ -5131,9 +5131,9 @@
|
|
|
5131
5131
|
return __awaiter(this, void 0, void 0, function* () {
|
|
5132
5132
|
const { nodeSize, align, rankdir = 'TB', ranksep, nodesep, edgeLabelSpace, ranker = 'tight-tree', nodeOrder, begin, controlPoints, radial, sortByCombo,
|
|
5133
5133
|
// focusNode,
|
|
5134
|
-
preset, } = options;
|
|
5135
|
-
const ranksepfunc = formatNumberFn(
|
|
5136
|
-
const nodesepfunc = formatNumberFn(
|
|
5134
|
+
preset, ranksepFunc, nodesepFunc, } = options;
|
|
5135
|
+
const ranksepfunc = formatNumberFn(ranksepFunc, ranksep !== null && ranksep !== void 0 ? ranksep : 50);
|
|
5136
|
+
const nodesepfunc = formatNumberFn(nodesepFunc, nodesep !== null && nodesep !== void 0 ? nodesep : 50);
|
|
5137
5137
|
let horisep = nodesepfunc;
|
|
5138
5138
|
let vertisep = ranksepfunc;
|
|
5139
5139
|
if (rankdir === 'LR' || rankdir === 'RL') {
|
|
@@ -5148,9 +5148,10 @@
|
|
|
5148
5148
|
const edges = this.model.edges();
|
|
5149
5149
|
nodes.forEach((node) => {
|
|
5150
5150
|
var _a;
|
|
5151
|
-
const
|
|
5152
|
-
const
|
|
5153
|
-
const
|
|
5151
|
+
const raw = node._original;
|
|
5152
|
+
const size = parseSize(nodeSizeFunc(raw));
|
|
5153
|
+
const verti = vertisep(raw);
|
|
5154
|
+
const hori = horisep(raw);
|
|
5154
5155
|
const width = size[0] + 2 * hori;
|
|
5155
5156
|
const height = size[1] + 2 * verti;
|
|
5156
5157
|
const layer = (_a = node.data) === null || _a === void 0 ? void 0 : _a.layer;
|
|
@@ -5216,6 +5217,7 @@
|
|
|
5216
5217
|
acyclicer: 'greedy',
|
|
5217
5218
|
ranker,
|
|
5218
5219
|
rankdir,
|
|
5220
|
+
nodesep,
|
|
5219
5221
|
align,
|
|
5220
5222
|
});
|
|
5221
5223
|
const layoutTopLeft = [0, 0];
|
|
@@ -7320,25 +7322,17 @@
|
|
|
7320
7322
|
}
|
|
7321
7323
|
|
|
7322
7324
|
const DEFAULTS_LAYOUT_OPTIONS$6 = {
|
|
7323
|
-
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
|
|
7327
|
-
|
|
7325
|
+
link: {
|
|
7326
|
+
id: (d) => String(d.id),
|
|
7327
|
+
},
|
|
7328
|
+
manyBody: {
|
|
7329
|
+
strength: -30,
|
|
7330
|
+
},
|
|
7328
7331
|
preventOverlap: false,
|
|
7329
7332
|
nodeSize: 10,
|
|
7330
7333
|
nodeSpacing: 0,
|
|
7331
|
-
|
|
7332
|
-
|
|
7333
|
-
nodeStrength: -30,
|
|
7334
|
-
distanceMin: undefined,
|
|
7335
|
-
distanceMax: undefined,
|
|
7336
|
-
theta: undefined,
|
|
7337
|
-
alpha: 1,
|
|
7338
|
-
alphaMin: 0.001,
|
|
7339
|
-
alphaDecay: 1 - Math.pow(0.001, 1 / 300),
|
|
7340
|
-
alphaTarget: 0,
|
|
7341
|
-
velocityDecay: 0.4,
|
|
7334
|
+
x: false,
|
|
7335
|
+
y: false,
|
|
7342
7336
|
clustering: false,
|
|
7343
7337
|
clusterNodeStrength: -1,
|
|
7344
7338
|
clusterEdgeStrength: 0.1,
|
|
@@ -7555,20 +7549,17 @@
|
|
|
7555
7549
|
this.setupClusterForce(simulation, options);
|
|
7556
7550
|
}
|
|
7557
7551
|
getCenterOptions(options) {
|
|
7558
|
-
if (
|
|
7559
|
-
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
|
|
7563
|
-
|
|
7564
|
-
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
});
|
|
7570
|
-
}
|
|
7571
|
-
return undefined;
|
|
7552
|
+
if (options.center === false)
|
|
7553
|
+
return undefined;
|
|
7554
|
+
const viewport = normalizeViewport({
|
|
7555
|
+
width: options.width,
|
|
7556
|
+
height: options.height,
|
|
7557
|
+
});
|
|
7558
|
+
return assignDefined({}, options.center || {}, {
|
|
7559
|
+
x: viewport.width / 2,
|
|
7560
|
+
y: viewport.height / 2,
|
|
7561
|
+
strength: options.centerStrength,
|
|
7562
|
+
});
|
|
7572
7563
|
}
|
|
7573
7564
|
setupCenterForce(simulation, options) {
|
|
7574
7565
|
const center = this.getCenterOptions(options);
|
|
@@ -7592,19 +7583,14 @@
|
|
|
7592
7583
|
}
|
|
7593
7584
|
}
|
|
7594
7585
|
getManyBodyOptions(options) {
|
|
7595
|
-
if (options.manyBody
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
options.
|
|
7599
|
-
options.
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
distanceMax: options.distanceMax,
|
|
7604
|
-
theta: options.theta,
|
|
7605
|
-
});
|
|
7606
|
-
}
|
|
7607
|
-
return undefined;
|
|
7586
|
+
if (options.manyBody === false)
|
|
7587
|
+
return undefined;
|
|
7588
|
+
return assignDefined({}, options.manyBody || {}, {
|
|
7589
|
+
strength: options.nodeStrength,
|
|
7590
|
+
distanceMin: options.distanceMin,
|
|
7591
|
+
distanceMax: options.distanceMax,
|
|
7592
|
+
theta: options.theta,
|
|
7593
|
+
});
|
|
7608
7594
|
}
|
|
7609
7595
|
setupManyBodyForce(simulation, options) {
|
|
7610
7596
|
const manyBody = this.getManyBodyOptions(options);
|
|
@@ -7630,19 +7616,14 @@
|
|
|
7630
7616
|
}
|
|
7631
7617
|
}
|
|
7632
7618
|
getLinkOptions(options) {
|
|
7633
|
-
if (options.link
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
options.
|
|
7637
|
-
options.
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
strength: options.edgeStrength,
|
|
7642
|
-
iterations: options.edgeIterations,
|
|
7643
|
-
});
|
|
7644
|
-
}
|
|
7645
|
-
return undefined;
|
|
7619
|
+
if (options.link === false)
|
|
7620
|
+
return undefined;
|
|
7621
|
+
return assignDefined({}, options.link || {}, {
|
|
7622
|
+
id: options.edgeId,
|
|
7623
|
+
distance: options.linkDistance,
|
|
7624
|
+
strength: options.edgeStrength,
|
|
7625
|
+
iterations: options.edgeIterations,
|
|
7626
|
+
});
|
|
7646
7627
|
}
|
|
7647
7628
|
setupLinkForce(simulation, options) {
|
|
7648
7629
|
const edges = this.model.edges();
|
|
@@ -7669,23 +7650,16 @@
|
|
|
7669
7650
|
}
|
|
7670
7651
|
}
|
|
7671
7652
|
getCollisionOptions(options) {
|
|
7672
|
-
if (
|
|
7653
|
+
if (options.preventOverlap === false || options.collide === false)
|
|
7673
7654
|
return undefined;
|
|
7674
|
-
|
|
7675
|
-
options.nodeSize
|
|
7676
|
-
|
|
7677
|
-
|
|
7678
|
-
options.
|
|
7679
|
-
|
|
7680
|
-
|
|
7681
|
-
|
|
7682
|
-
return assignDefined({}, options.collide || {}, {
|
|
7683
|
-
radius,
|
|
7684
|
-
strength: options.collideStrength,
|
|
7685
|
-
iterations: options.collideIterations,
|
|
7686
|
-
});
|
|
7687
|
-
}
|
|
7688
|
-
return undefined;
|
|
7655
|
+
const radius = options.nodeSize || options.nodeSpacing
|
|
7656
|
+
? (d) => formatNodeSizeFn(options.nodeSize, options.nodeSpacing)(d._original) / 2
|
|
7657
|
+
: undefined;
|
|
7658
|
+
return assignDefined({}, options.collide || {}, {
|
|
7659
|
+
radius: options.collide || radius,
|
|
7660
|
+
strength: options.collideStrength,
|
|
7661
|
+
iterations: options.collideIterations,
|
|
7662
|
+
});
|
|
7689
7663
|
}
|
|
7690
7664
|
setupCollisionForce(simulation, options) {
|
|
7691
7665
|
const collide = this.getCollisionOptions(options);
|
|
@@ -7710,18 +7684,13 @@
|
|
|
7710
7684
|
}
|
|
7711
7685
|
getXForceOptions(options) {
|
|
7712
7686
|
var _a;
|
|
7713
|
-
if (options.x
|
|
7714
|
-
|
|
7715
|
-
|
|
7716
|
-
|
|
7717
|
-
options.
|
|
7718
|
-
|
|
7719
|
-
|
|
7720
|
-
x: (_a = options.forceXPosition) !== null && _a !== void 0 ? _a : (center && center.x),
|
|
7721
|
-
strength: options.forceXStrength,
|
|
7722
|
-
});
|
|
7723
|
-
}
|
|
7724
|
-
return undefined;
|
|
7687
|
+
if (options.x === false)
|
|
7688
|
+
return undefined;
|
|
7689
|
+
const center = this.getCenterOptions(options);
|
|
7690
|
+
return assignDefined({}, options.x || {}, {
|
|
7691
|
+
x: (_a = options.forceXPosition) !== null && _a !== void 0 ? _a : (center && center.x),
|
|
7692
|
+
strength: options.forceXStrength,
|
|
7693
|
+
});
|
|
7725
7694
|
}
|
|
7726
7695
|
setupXForce(simulation, options) {
|
|
7727
7696
|
const x = this.getXForceOptions(options);
|
|
@@ -7744,18 +7713,13 @@
|
|
|
7744
7713
|
}
|
|
7745
7714
|
getYForceOptions(options) {
|
|
7746
7715
|
var _a;
|
|
7747
|
-
if (options.y
|
|
7748
|
-
|
|
7749
|
-
|
|
7750
|
-
|
|
7751
|
-
options.
|
|
7752
|
-
|
|
7753
|
-
|
|
7754
|
-
y: (_a = options.forceYPosition) !== null && _a !== void 0 ? _a : (center && center.y),
|
|
7755
|
-
strength: options.forceYStrength,
|
|
7756
|
-
});
|
|
7757
|
-
}
|
|
7758
|
-
return undefined;
|
|
7716
|
+
if (options.y === false)
|
|
7717
|
+
return undefined;
|
|
7718
|
+
const center = this.getCenterOptions(options);
|
|
7719
|
+
return assignDefined({}, options.y || {}, {
|
|
7720
|
+
y: (_a = options.forceYPosition) !== null && _a !== void 0 ? _a : (center && center.y),
|
|
7721
|
+
strength: options.forceYStrength,
|
|
7722
|
+
});
|
|
7759
7723
|
}
|
|
7760
7724
|
setupYForce(simulation, options) {
|
|
7761
7725
|
const y = this.getYForceOptions(options);
|
|
@@ -32799,7 +32763,6 @@ ${indent}columns: ${matrix.columns}
|
|
|
32799
32763
|
exports.isArray = isArray;
|
|
32800
32764
|
exports.isLayoutWithIterations = isLayoutWithIterations;
|
|
32801
32765
|
exports.johnson = johnson;
|
|
32802
|
-
exports.mergeOptions = mergeOptions;
|
|
32803
32766
|
exports.normalizeViewport = normalizeViewport;
|
|
32804
32767
|
exports.orderByDegree = orderByDegree;
|
|
32805
32768
|
exports.orderById = orderById;
|