D3.js强制布局 - 边缘标签放置/旋转

Mat*_*vic 10 javascript label d3.js force-layout

我对D3.js很新,而且我一直在玩力布局.我试过的一件事就是在链接上放置标签.

一种方法是通过附加svg:text和手动计算translate&rotate,它可以用直线工作.但是,如果链接是一个svg:path(例如弧),这不会按预期工作.在这些情况下,svg:textPath建议解决方案.

本演示中,您可以看到向链接添加标签的简单实现svg:textPath.唯一的问题是,如果源位于目标的右侧,则文本以相反的方向呈现(从我们的角度来看,它从路径的角度来看仍然是正确的).我的问题是,如何处理这个问题?

我想出的唯一"解决方案"是,在上述情况下手动交换源和目标.在这里,你可以看到它几乎可以工作.

在此输入图像描述

在交换发生的状态下,您还可以看到弧线翻转到另一侧,这看起来并不正确.:(

nra*_*itz 9

@LarsKotthoff是正确的,textPath必须遵循路径的方向.在这种情况下,路径的方向不仅定义了弧形方向,而且定义了箭头标记在末端的附着 - 这使得在飞行中交换方向变得棘手,因为您也必须移动标记.

更简单的解决方案(尽管如果你有大量的链接可能不是最好的)是使用仅用于文本的不可见路径"遮蔽"真实的链接路径:

var link = svg.append("svg:g").selectAll("g.link")
    .data(force.links())
  .enter().append('g')
    .attr('class', 'link');

var linkPath = link.append("svg:path")
    .attr("class", function(d) { return "link " + d.type; })
    .attr("marker-end", function(d) { return "url(#" + d.type + ")"; });

var textPath = link.append("svg:path")
    .attr("id", function(d) { return d.source.index + "_" + d.target.index; })
    .attr("class", "textpath");
Run Code Online (Sandbox Code Playgroud)

现在您有一个可以正确操作的独立路径.正如您所注意到的,有两个问题 - 您必须更改路径方向,并且必须更改圆弧方向.看起来你可以通过交换sweep-flag值在路径命令字符串中执行此操作(请参阅docs),所以不要Arx,ry 0 0,1Arx,ry 0 0,0.您可以通过使用一个函数来创建路径字符串来减少一些代码重复:

function arcPath(leftHand, d) {
    var start = leftHand ? d.source : d.target,
        end = leftHand ? d.target : d.source,
        dx = end.x - start.x,
        dy = end.y - start.y,
        dr = Math.sqrt(dx * dx + dy * dy),
        sweep = leftHand ? 0 : 1;
    return "M" + start.x + "," + start.y + "A" + dr + "," + dr +
        " 0 0," + sweep + " " + end.x + "," + end.y;
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以单独更新链接路径和文本路径:

linkPath.attr("d", function(d) {
    return arcPath(false, d);
});

textPath.attr("d", function(d) {
    return arcPath(d.source.x < d.target.x, d);
});
Run Code Online (Sandbox Code Playgroud)

参见工作代码:http://jsfiddle.net/nrabinowitz/VYaGg/2/

  • 另一种表达方式:一般来说,我可能会为完全糟糕的做法而投票,但不是因为缺乏最佳实践(除非OP特别要求最佳实践). (2认同)