如何在 d3 中绘制 graphviz 样条曲线

How to draw a graphviz spline in d3

背景

graphviz 非常适合布置图表。当我用 graphviz“点”布局我的图形时,它会生成一个文件,其中的节点和边缘标有位置。例如。一条边:

"a" -> "b"   [pos="e,152.13,411.67 91.566,463.4 108.12,449.26 127.94,432.34 144.37,418.3"];

Graphviz spline language如下:

 spline       =   (endp)? (startp)? point (triple)+
 and triple   =   point point point
 and endp     =   "e,%f,%f"
 and startp   =   "s,%f,%f"

If a spline has points p1 p2 p3 ... pn, (n = 1 (mod 3)), the points correspond to the control points of a cubic B-spline from p1 to pn. If startp is given, it touches one node of the edge, and the arrowhead goes from p1 to startp. If startp is not given, p1 touches a node. Similarly for pn and endp.

所以分解上面的字符串,

e,152.13,411.67   // This is an endpoint. 
91.566,463.4      // p1
108.12,449.26     // the following three points are control points for a cubic b-spline
127.94,432.34
144.37,418.3

问题

我想通过d3画这条样条线。 d3 似乎 cubic b-splines 具有以下签名:

d3.curveBasis(context)

Produces a cubic basis spline using the specified control points. The first and last points are triplicated such that the spline starts at the first point and ends at the last point, and is tangent to the line between the first and second points, and to the line between the penultimate and last points.

那么我该如何取字符串

[pos="e,152.13,411.67 91.566,463.4 108.12,449.26 127.94,432.34 144.37,418.3"];

然后绘制 graphviz 在 d3 中绘制的样条线?

原来是我想多了。

如果将 e(端点)移动到点数组的末尾,d3.curveBasis() 会完美地呈现它。

# G is a networkx graph and A is a pygraphviz graph
for e in G.edges():
    points = A.get_edge(e[0], e[1]).attr["pos"].lstrip('e,').split(' ')
    points.append(points.pop(0))
    G.edges[e[0], e[1]].update({'points': [{'x':float(p.split(',')[0]), 'y':float(p.split(',')[1])} for p in points]})

之后:

var lineGenerator = d3.line().y(d => d.y).x(d => d.x).curve(d3.curveBasis);

link.enter()
    .append('path')
    .attr('d', l => lineGenerator(l.points))