如何在 cytoscape.js 中使用贝塞尔曲线

how to use bezier curves in cytoscape.js

好了,别笑了。我试图制作弯曲的边缘,绕过源和目标之间的节点。我想不通该怎么做(我读了http://js.cytoscape.org/#style/bezier-edges,但没看懂),所以我在从源到目标的途中把假节点放到空的地方,做了一系列的边。结果很荒谬:

正确的做法是什么?我的目标是稍微优雅一些​​,比如:

from http://twitter.github.io/labella.js/

根据下面@maxkfranz的建议,我确实离得更近了:

但最终决定放弃。时间太长了。回到直线边缘。如果有人读过这篇文章并且可以描述一种在 Cytoscape.js 或其他工具中实现我的目标的方法,我很乐意听到它。

为了在放弃之前弄清楚我在做什么,我:

这是我的代码中最相关的部分:

  function waypoints(from, to) {
    let stubPoint = { row: from.data().row, col: from.data().col, 
                      distance: 0, weight: .5, };
    if (from.data().layer === to.data().layer)
      return [stubPoint];
    let fromCol = from.data().col, 
        curCol = fromCol,
        toCol = to.data().col,
        fromRow = from.data().row,
        curRow = fromRow,
        toRow = to.data().row,
        fromX = from.position().x,
        fromY = from.position().y,
        toX = to.position().x,
        toY = to.position().y,
        x = d3.scaleLinear().domain([fromCol,toCol]).range([fromX,toX]),
        y = d3.scaleLinear().domain([fromRow,toRow]).range([fromY,toY]);
    let rowsBetween = _.range(fromRow, toRow).slice(1);
    let edgeLength = pointToPointDist(x(fromCol),y(fromRow),x(toCol),y(toRow));
    let points = rowsBetween.map(
      (nextRow,i) => {
        let colsRemaining = toCol - curCol;
        let colsNow = Math.ceil(colsRemaining / Math.abs(toRow - curRow));
        let nextCol = findEmptyGridCol(nextRow, curCol, curCol + colsNow);
        let curX = x(curCol), curY = y(curRow),
            nextX = x(nextCol), nextY = y(nextRow);
        let [distanceFromEdge, distanceOnEdge] = 
              perpendicular_coords(curX, curY, toX, toY, nextX, nextY);

        let point = {curCol, curRow, 
                      toCol, toRow,
                      nextCol, nextRow,
                      curX, curY, toX, toY, nextX, nextY,
                      edgeLength,
                      colsNow,
                      //wayCol, wayRow,
                      distance:-distanceFromEdge * 2, 
                      weight:distanceOnEdge / edgeLength,
                    };
        curCol = nextCol;
        curRow = nextRow;
        return point;
      });
    if (points.length === 0)
        return [stubPoint];
    return points;
  }

边的控制点集由 N 个权重定义 (w1, w2, ... wN)和N个各自的距离(d1,d2,...dN).

权重定义点与源或目标的距离,距离控制点与 source-target 线的距离。距离的符号控制曲线所在的 source-target 线的一侧(即旋向)。有关详细信息,请参阅文档:http://js.cytoscape.org/#style/bezier-edges

为简单起见,下图总结了单个点的值,但您可以将其扩展到多个点:

请注意,上图假设 edge-distances: node-position,而下图假设 edge-distances: intersection(默认值):

对于复杂的用例,edge-distances: node-position 使计算更容易——但您必须更加小心,不要在节点主体中指定点。这些示例的最终结果几乎相同,因此我没有更新曲线。不同大小的较大节点会使这些情况之间的差异更加明显。

贝塞尔曲线的控制点不与控制点相交。控制点"pulls" 曲线朝向该点。对于像 Cytoscape 中的二次贝塞尔曲线,曲线的距离将是控制点的一半。有关贝塞尔曲线的更多信息,请参阅维基百科:https://en.wikipedia.org/wiki/B%C3%A9zier_curve

另一方面,线段边缘将与您指定的点相交,因为它们只是一系列直线:http://js.cytoscape.org/#style/segments-edges