Skip to content

Commit d7d569f

Browse files
committed
fix: edges placement when nodes are closed, increased distance between any two parallel edges
1 parent 9bc1dac commit d7d569f

3 files changed

Lines changed: 77 additions & 5 deletions

File tree

src/config/cytoscape-style.js

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,17 +59,40 @@ const style = [
5959
const source = ele.source();
6060
const target = ele.target();
6161

62+
// Check if there are parallel edges
63+
const parallelEdges = source.edgesWith(target);
64+
const hasParallelEdges = parallelEdges.length > 1;
65+
6266
// Get positions
6367
const p1 = source.position();
6468
const p2 = target.position();
6569

70+
// Calculate distance between nodes
71+
const distance = Math.sqrt(
72+
(p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2,
73+
);
74+
6675
// Calculate difference
6776
const dx = Math.abs(p1.x - p2.x);
6877
const dy = Math.abs(p1.y - p2.y);
6978

7079
// Define a threshold for what counts as "aligned"
7180
const threshold = 10;
7281

82+
// Check if edge has custom bend data
83+
const bendDistance = ele.data('bendData')?.bendDistance || 0;
84+
const hasBend = Math.abs(bendDistance) > 0;
85+
86+
// When nodes are very close, always use straight style to prevent edge disappearance
87+
if (distance < 50) {
88+
return 'straight';
89+
}
90+
91+
// For parallel edges or edges with bend, use bezier curves
92+
if (hasParallelEdges || hasBend) {
93+
return 'unbundled-bezier';
94+
}
95+
7396
// If aligned horizontally OR vertically, be straight
7497
if (dx < threshold || dy < threshold) {
7598
return 'straight';
@@ -78,16 +101,58 @@ const style = [
78101
// use unbundled-bezier to respect bend points
79102
return 'unbundled-bezier';
80103
},
81-
segmentDistances: 'data(bendData.bendDistance)',
104+
segmentDistances: (ele) => {
105+
// When nodes are very close, don't apply bend to prevent edge disappearance
106+
const source = ele.source();
107+
const target = ele.target();
108+
const p1 = source.position();
109+
const p2 = target.position();
110+
const distance = Math.sqrt(
111+
(p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2,
112+
);
113+
114+
if (distance < 50) {
115+
return 0;
116+
}
117+
118+
return ele.data('bendData.bendDistance');
119+
},
82120
segmentWeights: 'data(bendData.bendWeight)',
83121
edgeDistances: 'node-position',
84122
lineStyle: 'data(style.shape)',
123+
controlPointDistances: (ele) => {
124+
// For parallel edges, ensure adequate control point spacing
125+
const bendDistance = ele.data('bendData')?.bendDistance || 0;
126+
return Math.abs(bendDistance) > 0 ? bendDistance : undefined;
127+
},
128+
controlPointWeights: (ele) => {
129+
const bendWeight = ele.data('bendData')?.bendWeight;
130+
return bendWeight !== undefined ? bendWeight : 0.5;
131+
},
85132
},
86133
},
87134
{
88135
selector: 'edge[label]',
89136
style: {
90-
label: 'data(label)',
137+
label: (ele) => {
138+
// Get source and target nodes
139+
const source = ele.source();
140+
const target = ele.target();
141+
142+
// Calculate distance between nodes
143+
const p1 = source.position();
144+
const p2 = target.position();
145+
const distance = Math.sqrt(
146+
(p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2,
147+
);
148+
149+
// Define minimum distance threshold (in pixels)
150+
// Below this distance, hide the label to prevent visual clutter
151+
const minDistanceForLabel = 80;
152+
153+
// Return label only if nodes are far enough apart
154+
return distance >= minDistanceForLabel ? ele.data('label') : '';
155+
},
91156
edgeTextRotation: 'autorotate',
92157
zIndex: 999,
93158
fontSize: 12,

src/graph-builder/graph-core/1-core.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ class CoreGraph {
133133

134134
this.cy.gridGuide({
135135
snapToGridOnRelease: true,
136-
snapToGridDuringDrag: true,
136+
snapToGridDuringDrag: false,
137137
zoomDash: true,
138138
panGrid: true,
139139
gridSpacing: this.gridSize,

src/graph-builder/graph-core/3-component.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class GraphComponent extends GraphCanvas {
1616

1717
constructor(...args) {
1818
super(...args);
19-
const [,,,,, nodeValidator, edgeValidator] = args;
19+
const [, , , , , nodeValidator, edgeValidator] = args;
2020
this.setEdgeNodeValidator({ nodeValidator, edgeValidator });
2121
this.getTid = () => new Date().getTime();
2222
}
@@ -70,7 +70,14 @@ class GraphComponent extends GraphCanvas {
7070
if (targetID === edge.target().id()) dists.add(edge.data('bendData').bendDistance);
7171
else dists.add(-edge.data('bendData').bendDistance);
7272
});
73-
for (let d = 0; ;d += 20) {
73+
74+
// Calculate optimal spacing based on number of parallel edges
75+
// Base spacing of 60px, increasing with more edges for better visibility
76+
const edgeCount = edges.length;
77+
const baseSpacing = 100;
78+
const spacingIncrement = edgeCount > 4 ? baseSpacing * 1.5 : baseSpacing;
79+
80+
for (let d = 0; ; d += spacingIncrement) {
7481
if (!dists.has(d)) return d;
7582
if (!dists.has(-d)) return -d;
7683
}

0 commit comments

Comments
 (0)