capdag 0.187.479 → 0.188.482
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/cap-fab-renderer.js +96 -4
- package/package.json +1 -1
package/cap-fab-renderer.js
CHANGED
|
@@ -379,8 +379,12 @@ function layoutForMode(mode) {
|
|
|
379
379
|
};
|
|
380
380
|
if (mode === 'browse') {
|
|
381
381
|
return Object.assign({}, base, {
|
|
382
|
-
'elk.layered.spacing.nodeNodeBetweenLayers':
|
|
383
|
-
'elk.spacing.
|
|
382
|
+
'elk.layered.spacing.nodeNodeBetweenLayers': 220,
|
|
383
|
+
'elk.layered.spacing.edgeEdgeBetweenLayers': 44,
|
|
384
|
+
'elk.layered.spacing.edgeNodeBetweenLayers': 52,
|
|
385
|
+
'elk.spacing.edgeEdge': 34,
|
|
386
|
+
'elk.spacing.edgeNode': 42,
|
|
387
|
+
'elk.spacing.nodeNode': 118,
|
|
384
388
|
});
|
|
385
389
|
}
|
|
386
390
|
if (mode === 'strand') {
|
|
@@ -536,8 +540,10 @@ function buildStylesheet() {
|
|
|
536
540
|
// text no longer reads as floating metadata.
|
|
537
541
|
'text-rotation': 'autorotate',
|
|
538
542
|
'text-margin-y': -6,
|
|
539
|
-
'curve-style': '
|
|
540
|
-
'control-point-step-size':
|
|
543
|
+
'curve-style': 'data(curveStyle)',
|
|
544
|
+
'control-point-step-size': 'data(controlPointStepSize)',
|
|
545
|
+
'control-point-distances': 'data(controlPointDistances)',
|
|
546
|
+
'control-point-weights': 'data(controlPointWeights)',
|
|
541
547
|
'width': 1.5,
|
|
542
548
|
'line-color': 'data(color)',
|
|
543
549
|
'target-arrow-color': 'data(color)',
|
|
@@ -690,6 +696,12 @@ function assertArray(value, path) {
|
|
|
690
696
|
}
|
|
691
697
|
}
|
|
692
698
|
|
|
699
|
+
function assertObject(value, path) {
|
|
700
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
701
|
+
throw new Error(`CapFabRenderer: ${path} must be an object`);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
693
705
|
function validateBrowseData(data) {
|
|
694
706
|
assertArray(data, 'browse mode data');
|
|
695
707
|
data.forEach((cap, idx) => {
|
|
@@ -961,6 +973,81 @@ function edgeHueColor(edgeIdx) {
|
|
|
961
973
|
return `hsl(${hue}, 60%, 55%)`;
|
|
962
974
|
}
|
|
963
975
|
|
|
976
|
+
function centeredOrdinal(index, total) {
|
|
977
|
+
if (!Number.isInteger(index) || !Number.isInteger(total) || total <= 0) {
|
|
978
|
+
throw new Error('CapFabRenderer: centeredOrdinal requires integer index/total');
|
|
979
|
+
}
|
|
980
|
+
return index - ((total - 1) / 2);
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
function crowdOffsets(index, total, step, maxAbs) {
|
|
984
|
+
if (total <= 1) return 0;
|
|
985
|
+
const raw = centeredOrdinal(index, total) * step;
|
|
986
|
+
if (maxAbs === undefined) return raw;
|
|
987
|
+
return Math.max(-maxAbs, Math.min(maxAbs, raw));
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
function annotateCrowdedBrowseEdges(edges) {
|
|
991
|
+
const bySource = new Map();
|
|
992
|
+
const byTarget = new Map();
|
|
993
|
+
|
|
994
|
+
for (const edge of edges) {
|
|
995
|
+
if (!bySource.has(edge.source)) bySource.set(edge.source, []);
|
|
996
|
+
bySource.get(edge.source).push(edge);
|
|
997
|
+
if (!byTarget.has(edge.target)) byTarget.set(edge.target, []);
|
|
998
|
+
byTarget.get(edge.target).push(edge);
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
const stableSort = (a, b) => {
|
|
1002
|
+
const targetCmp = a.target.localeCompare(b.target);
|
|
1003
|
+
if (targetCmp !== 0) return targetCmp;
|
|
1004
|
+
const titleCmp = a.title.localeCompare(b.title);
|
|
1005
|
+
if (titleCmp !== 0) return titleCmp;
|
|
1006
|
+
return a.id.localeCompare(b.id);
|
|
1007
|
+
};
|
|
1008
|
+
const reverseStableSort = (a, b) => {
|
|
1009
|
+
const sourceCmp = a.source.localeCompare(b.source);
|
|
1010
|
+
if (sourceCmp !== 0) return sourceCmp;
|
|
1011
|
+
const titleCmp = a.title.localeCompare(b.title);
|
|
1012
|
+
if (titleCmp !== 0) return titleCmp;
|
|
1013
|
+
return a.id.localeCompare(b.id);
|
|
1014
|
+
};
|
|
1015
|
+
|
|
1016
|
+
for (const group of bySource.values()) group.sort(stableSort);
|
|
1017
|
+
for (const group of byTarget.values()) group.sort(reverseStableSort);
|
|
1018
|
+
|
|
1019
|
+
const sourceIndex = new Map();
|
|
1020
|
+
const targetIndex = new Map();
|
|
1021
|
+
for (const group of bySource.values()) {
|
|
1022
|
+
group.forEach((edge, idx) => sourceIndex.set(edge.id, idx));
|
|
1023
|
+
}
|
|
1024
|
+
for (const group of byTarget.values()) {
|
|
1025
|
+
group.forEach((edge, idx) => targetIndex.set(edge.id, idx));
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
for (const edge of edges) {
|
|
1029
|
+
const sourceGroup = bySource.get(edge.source) || [edge];
|
|
1030
|
+
const targetGroup = byTarget.get(edge.target) || [edge];
|
|
1031
|
+
const sourceCount = sourceGroup.length;
|
|
1032
|
+
const targetCount = targetGroup.length;
|
|
1033
|
+
const crowdCount = Math.max(sourceCount, targetCount);
|
|
1034
|
+
|
|
1035
|
+
if (crowdCount <= 2) {
|
|
1036
|
+
edge.curveStyle = 'bezier';
|
|
1037
|
+
edge.controlPointStepSize = 40;
|
|
1038
|
+
continue;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
const sourceOffset = crowdOffsets(sourceIndex.get(edge.id), sourceCount, 18, 64);
|
|
1042
|
+
const targetOffset = crowdOffsets(targetIndex.get(edge.id), targetCount, 18, 64);
|
|
1043
|
+
|
|
1044
|
+
edge.curveStyle = 'unbundled-bezier';
|
|
1045
|
+
edge.controlPointDistances = `${sourceOffset} ${targetOffset}`;
|
|
1046
|
+
edge.controlPointWeights = '0.22 0.78';
|
|
1047
|
+
edge.controlPointStepSize = 56;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
|
|
964
1051
|
// --------- Browse mode builder ----------------------------------------------
|
|
965
1052
|
|
|
966
1053
|
function buildBrowseGraphData(capabilities) {
|
|
@@ -1014,6 +1101,7 @@ function buildBrowseGraphData(capabilities) {
|
|
|
1014
1101
|
edges.forEach((edge, i) => {
|
|
1015
1102
|
edge.color = edgeHueColor(i);
|
|
1016
1103
|
});
|
|
1104
|
+
annotateCrowdedBrowseEdges(edges);
|
|
1017
1105
|
|
|
1018
1106
|
const nodes = Array.from(nodesMap.values());
|
|
1019
1107
|
for (const node of nodes) {
|
|
@@ -1061,6 +1149,10 @@ function browseCytoscapeElements(built) {
|
|
|
1061
1149
|
fullUrn: edge.capability.urn,
|
|
1062
1150
|
capFabEdgeIndex: edge.capFabEdgeIndex,
|
|
1063
1151
|
color: edge.color,
|
|
1152
|
+
curveStyle: edge.curveStyle || 'bezier',
|
|
1153
|
+
controlPointStepSize: edge.controlPointStepSize || 40,
|
|
1154
|
+
controlPointDistances: edge.controlPointDistances || '',
|
|
1155
|
+
controlPointWeights: edge.controlPointWeights || '',
|
|
1064
1156
|
},
|
|
1065
1157
|
};
|
|
1066
1158
|
});
|
package/package.json
CHANGED