问题
I'd like to share with community an useful function that returns segment-distances and segment-weights from a coordinate (PointX, PointY).
I create diagrams from tool (such as draw.io) and when making edge (segment style) with multiple waypoints, the freeware provides waypoints by its coordinates. Unfortunately latest version of cytoscape.js (at the time I wrote this post) dont include this capability (apologies if it does) and only segment-distances and segment-weights are used.
Therefore I created the below function that returns both segment-distances and segment-weights values using source (sX, sY), target (tX, tY) and its waypoint (PointX, PointY). This function could also be used for multiple waypoints as well. The result is pretty good except that lines appearing orthogonals on freeware (draw.io) dont appear perfectly orthogonals via cytoscape.js. Need to work out on that aspect !
function getDistWeight(sX, sY, tX, tY, PointX, PointY){
var W, D;
D = ( PointY - sY + (sX-PointX) * (sY-tY) / (sX-tX) ) / Math.sqrt( 1 + Math.pow((sY-tY) / (sX-tX), 2) );
W = Math.sqrt( Math.pow(PointY-sY,2) + Math.pow(PointX-sX,2) - Math.pow(D,2) );
var distAB = Math.sqrt(Math.pow(tX-sX, 2) + Math.pow(tY-sY, 2));
W = W / distAB;
//check whether the point (PointX, PointY) is on right or left of the line src to tgt. for instance : a point C(X, Y) and line (AB). d=(xB-xA)(yC-yA)-(yB-yA)(xC-xA). if d>0, then C is on left of the line. if d<0, it is on right. if d=0, it is on the line.
var delta1 = (tX-sX)*(PointY-sY)-(tY-sY)*(PointX-sX);
switch (true) {
case (delta1 >= 0) :
delta1 = 1;
break;
case (delta1 < 0) :
delta1 = -1;
break;
}
//check whether the point (PointX, PointY) is "behind" the line src to tgt
var delta2 = (tX-sX)*(PointX-sX)+(tY-sY)*(PointY-sY);
switch (true) {
case (delta2 >= 0) :
delta2 = 1;
break;
case (delta2 < 0) :
delta2 = -1;
break;
}
D = Math.abs(D) * delta1; //ensure that sign of D is same as sign of delta1. Hence we need to take absolute value of D and multiply by delta1
W = W * delta2;
return {
ResultDistance: D,
ResultWeight: W
};
}
var point = getDistWeight(10, 5, 25, 15, 9, 6);
console.log(point);
回答1:
I used your function and was finally able to get orthogonal edges. There are 2 things that are needed for this:
- You need to declare "edge-distance" in your edge's style as "node-position"
- You need to call your function with edge's source position and edge's target position, and the point you wants, but expressed with edge's endpoints position (see documentation here).
Example below will produce this graph:
The style to add to cytoscape config:
selector: 'edge',
style: {
'curve-style': 'segments',
"segment-weights": '0.5',
'segment-distances': '0',
'edge-distances': 'node-position',
'source-endpoint': '180deg',
'target-endpoint': '0deg'
}
The code that will compute the inflection point for each edge:
// batch modifications to avoid rendering during changes
cytoscape.startBatch()
// get all edges from the graph
let edges = cytoscape.edges()
for (let edge of Object.values(edges)) {
if (edge.data) {
// get nodes positions for source and target
let src = edge.source().position()
let tgt = edge.target().position()
// get endpoints positions for source and target
let srcEp = edge.sourceEndpoint()
let tgtEp = edge.targetEndpoint()
if (src.x == tgt.x) {
// do nothing, nodes are aligned vertically
}
else {
// compute weight and distance for the point that will be added to the edge
// the point will be added aligned horizontally with "source endpoint", and vertically 25px above target endpoint
let point = getDistWeight(src.x, src.y, tgt.x, tgt.y, srcEp.x, tgtEp.y - 25);
// set the values
edge.style('segment-distances', ''+point.ResultDistance)
edge.style('segment-weights', ''+point.ResultWeight)
}
}
}
cytoscape.endBatch()
来源:https://stackoverflow.com/questions/53622515/cytoscape-js-for-edge-segment-transforming-coordinates-onto-segment-distances