Add weighted cross-chord edges: 100x weaker than regular edges

This commit is contained in:
Michael Winter 2026-04-01 17:48:47 +02:00
parent ab7e949f07
commit 7259cd67bd

View file

@ -46,18 +46,23 @@
});
});
const edgeList = edges.map(e => ({ s: e.source().id(), t: e.target().id() }));
const edgeList = edges.map(e => ({
s: e.source().id(),
t: e.target().id(),
isCrossChord: e.data('isCrossChord')
}));
const iter = (i) => {
state.forEach(s => s.fx = 0);
edgeList.forEach(({s,t})=>{
edgeList.forEach(({s, t, isCrossChord})=>{
const a = state.get(s), b = state.get(t);
if(!a || !b) return;
const dx = b.x - a.x;
const dist = Math.abs(dx) || 0.0001;
const dir = dx / dist;
const spring = opts.linkStrength * (dist - opts.linkDistance);
const strength = isCrossChord ? (opts.crossChordStrength || 0.001) : opts.linkStrength;
const spring = strength * (dist - opts.linkDistance);
a.fx += spring * dir;
b.fx -= spring * dir;
});
@ -350,8 +355,8 @@
{
selector: 'edge',
style: {
'width': 1.5,
'line-color': '#555555',
'width': 2.5,
'line-color': '#ffffff',
'curve-style': 'straight',
'target-arrow-shape': 'none',
'label': 'data(ratio)',
@ -364,6 +369,17 @@
'text-background-padding': '2px',
}
},
{
selector: 'edge[isCrossChord = "true"]',
style: {
'width': 1,
'line-color': '#aaaaaa',
'line-style': 'dashed',
'curve-style': 'straight',
'target-arrow-shape': 'none',
'label': '',
}
},
{
selector: ':selected',
style: {
@ -479,6 +495,33 @@
// Build elements array for all chords
let elements = [];
// Collect cross-chord edges (same hs_array between adjacent chords)
const crossChordEdges = [];
for (let chordIdx = 1; chordIdx < allGraphsData.graphs.length; chordIdx++) {
const prevGraph = allGraphsData.graphs[chordIdx - 1];
const currGraph = allGraphsData.graphs[chordIdx];
if (!prevGraph || !prevGraph.nodes || !currGraph || !currGraph.nodes) continue;
currGraph.nodes.forEach(n => {
const prevNode = prevGraph.nodes.find(pn =>
JSON.stringify(pn.hs_array) === JSON.stringify(n.hs_array)
);
if (prevNode) {
const prevNodeId = `c${chordIdx - 1}_${prevNode.id}`;
const currNodeId = `c${chordIdx}_${n.id}`;
crossChordEdges.push({
group: 'edges',
data: {
source: prevNodeId,
target: currNodeId,
ratio: "1/1",
isCrossChord: "true"
},
});
}
});
}
allGraphsData.graphs.forEach((graph, chordIdx) => {
if (!graph || !graph.nodes) return;
@ -527,6 +570,9 @@
if (elements.length === 0) return;
// Add cross-chord edges to elements BEFORE layout (so xforce considers them)
elements.push(...crossChordEdges);
// Add all elements
cy.add(elements);
console.log('Added', elements.length, 'elements');
@ -544,16 +590,19 @@
});
// Run xforce layout to optimize x positions while keeping y fixed
cy.layout({
const layout = cy.layout({
name: 'xforce',
linkDistance: 60,
linkStrength: 0.1,
crossChordStrength: 0.00005,
charge: -60,
collisionDistance: 35,
damping: 0.7,
iterations: 250,
bounds: bounds,
}).run();
});
layout.run();
// Set canvas size
cy.style().json()[0].value = graphWidth;