如何在Sankey图(D3.JS)中的节点上垂直对齐文本?

时间:2014-05-02 18:41:16

标签: javascript svg d3.js label sankey-diagram

我修改了来自http://bost.ocks.org/mike/sankey/的D3.Js中的Sankey图的Mike Bostok示例,以显示每个节点的值:

Sankey http://uweb.cs.uvic.ca/~maleh2/sankey.png

node.append("text")
    .attr("class","nodeValue");

///align vertically??
node.selectAll("text.nodeValue")
    .attr("x", sankey.nodeWidth() / 2)
    .attr("y", function (d) { return (d.dy / 2) })
    .text(function (d) { return formatNumber(d.value); })
    .attr("text-anchor", "middle");
    //.attr("transform", "rotate(-90)")

迈克的例子和我的修改的所有代码都在jsfiddle (http://jsfiddle.net/4xNK5/)。我的问题是如何垂直显示节点的值?我假设一个简单的.attr(“transform”,“rotate(-90)”);会做的。实际上,我得到的节点的值垂直对齐但不合适。我无法理解它背后的逻辑。任何想法将不胜感激......

1 个答案:

答案 0 :(得分:14)

我将带您完成几个实验(所有这些实验都伴随着jsfiddles),它将指导您解决问题。

起点

click for jsfiddle

这是您问题中略有修改的示例:

enter image description here

它已被修改,因此它包含JavaScript而不是JSON文件中的数据,并且它还包含来自Sankey插件的代码。这只是为了在JsFiddle中有工作示例。您当然可以调整它以满足您对数据等的需求......

正如您已经提到的那样,关键代码在这里:

  node.selectAll("text.nodeValue")
      .attr("x", sankey.nodeWidth() / 2)
      .attr("y", function (d) { return (d.dy / 2) })
      .text(function (d) { return formatNumber(d.value); })
      .attr("text-anchor", "middle");

实验1

click for jsfiddle

我真的很困扰节点的值和名称没有对齐,所以我添加了这个稍微向下移动值的代码:

      .attr("dy", 5)

结果在这里:

enter image description here


实验2

click for jsfiddle

现在让我们尝试添加此代码(我故意使用45度来更容易地发现旋转的工作原理):

      .attr("transform", "rotate(-45)")

令人惊讶的是,我们得到了这个:

enter image description here

如果我们检查firebug或类似工具中的html / svg,我们会注意到这种旋转行为的原因是值标签实际上是其他容器的一部分:(并且旋转中心不是标签的中心,但那个容器的起源)

enter image description here


实验3

click for jsfiddle

在这个实验中,我想避免使用旋转。我想使用svg text property writing-mode,如下所示:

      .style("writing-mode", "tb")

我得到了这个:

enter image description here

但是,我无法将值标签定位为左上角。另外,我听说这种方法有一些Firefox兼容性问题,所以我放弃了。


解决方案

click for jsfiddle

在上面的实验之后,我的结论是应该首先进行旋转,并且应该应用该平移,以便已经旋转的值标签移动到节点的中心。由于此转换与数据有关,因此代码应如下所示:

  node.selectAll("text.nodeValue")
      .text(function (d) { return formatNumber(d.value); })
      .attr("text-anchor", "middle")
      .attr("transform", function (d) {
           return "rotate(-90) translate(" +
                       (-d.dy / 2) +
                       ", " +
                       (sankey.nodeWidth() / 2 + 5) +
       ")";});

结果是:

enter image description here