【问题标题】:D3.js force layout - edge label placement/rotationD3.js 强制布局 - 边缘标签放置/旋转
【发布时间】:2013-08-21 09:11:33
【问题描述】:

我是 D3.js 的新手,我一直在玩力布局。我尝试的其中一件事是在链接上放置标签。

一种方法是附加svg:text 并手动计算translaterotate,这适用于直线。但是,如果链接是 svg:path(例如 arc),这将无法按预期工作。在这些情况下,建议使用svg:textPath 解决方案。

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

我想出的唯一“解决方案”是,在上述情况下手动交换源和目标。 Here,您可以看到它几乎有效。

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

【问题讨论】:

  • 您不能为textPath 指定文本方向——文本始终遵循路径的方向。因此,您拥有的解决方案是唯一可行的解​​决方案。

标签: javascript d3.js label force-layout


【解决方案1】:

@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");

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

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;
}

然后可以分别更新链接路径和文本路径:

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

textPath.attr("d", function(d) {
    return arcPath(d.source.x < d.target.x, d);
});

查看工作代码:http://jsfiddle.net/nrabinowitz/VYaGg/2/

【讨论】:

  • 不建议在数据连接中为每个数据元素创建多个节点。如果/当您更新数据并再次执行连接时,它将导致意外行为。以下是有关原因的更多详细信息:stackoverflow.com/questions/10808320/…
  • 点了,但如果您不打算稍后动态更新数据,这样做是完全可以接受的——通常是网络图的情况,并且 OP 没有提到更新。我会更新我的答案,但我不认为原来的方法是不正确的,而且我认为仅仅因为你不喜欢这种方法而投反对票是一种糟糕的形式。
  • 不确定它是否是糟糕的形式。我仍在尝试在 SO 中投票。我的理由是,虽然您在有限的示例中这样做在技术上是正确的,但它鼓励了一种通常不会起作用的编码实践。我的经验是,数据连接是 d3 中最容易被图书馆新手误解的部分之一,所以我觉得对于展示数据连接技术的答案应该特别严格,以鼓励和促进对这种基本机制的普遍理解。当然,这只是我的看法。
  • 好吧,是否投反对票取决于你,我明白你的意思——我想分歧在于我最初的反应是否真的在促进不良实践,或者在有限的范围内它是否完全合理范围。无论哪种方式,如果您在响应您的建议而更新答案时放弃投反对票,通常会受到赞赏(因为它不再令人反感)。
  • 另一种说法:一般来说,我可能会因为完全糟糕的做法而投反对票,但不会因为缺乏最佳做法而投反对票(除非 OP 专门要求最佳做法)。
猜你喜欢
  • 1970-01-01
  • 2017-05-04
  • 2014-04-29
  • 1970-01-01
  • 1970-01-01
  • 2017-06-27
  • 2016-08-15
  • 1970-01-01
  • 2013-04-20
相关资源
最近更新 更多