2012-08-08 129 views
51

我从d3.js开始,尝试创建一个节点行,每个节点包含一个居中的数字标签。将标签放置在d3.js节点的中心

我能够以可视方式产生所需的结果,但是我做到这一点的方式几乎不是最佳的,因为它涉及硬编码每个文本元素的x-y坐标。下面是代码:

var svg_w = 800; 
var svg_h = 400; 
var svg = d3.select("body") 
    .append("svg") 
    .attr("width", svg_w) 
    .attr("weight", svg_h); 

var dataset = []; 
for (var i = 0; i < 6; i++) { 
    var datum = 10 + Math.round(Math.random() * 20); 
    dataset.push(datum); 
} 

var nodes = svg.append("g") 
       .attr("class", "nodes") 
       .selectAll("circle") 
       .data(dataset) 
       .enter() 
       .append("circle") 
       .attr("class", "node") 
       .attr("cx", function(d, i) { 
        return (i * 70) + 50; 
       }) 
       .attr("cy", svg_h/2) 
       .attr("r", 20); 

var labels = svg.append("g") 
       .attr("class", "labels") 
       .selectAll("text") 
       .data(dataset) 
       .enter() 
       .append("text") 
       .attr("dx", function(d, i) { 
        return (i * 70) + 42 
       }) 
       .attr("dy", svg_h/2 + 5) 
       .text(function(d) { 
        return d; 
       }); 

node类是我为circle元素单独定义自定义CSS类,而类nodeslabels没有明确定义,他们是从这个answer借来的。

如图所示,每个文本标签的位置都是硬编码的,因此它出现在每个节点的中心。显然,这不是正确的解决方案。

我的问题是,我应该如何正确地将每个文本标签与每个节点圆圈动态关联,以便如果标签的位置随着圆的位置自动变化。代码示例非常欢迎概念性解释。

+1

锚文本似乎没有直接D3工作还没有,但你尝试作为CSS文本对齐简单的东西?这应该做的伎俩! http://www.w3schools.com/cssref/pr_text_text-align.asp另请尝试查看d3 Google群组中的这类帖子:https://groups.google.com/forum/#!searchin/d3 -js/text-align/d3-js/M6a-97ajkWs/rHJV4_WrhX0J%5B1-25%5D – paxRoman 2012-08-08 08:39:59

+1

你在哪里得到文字定位符在d3中不起作用的想法? – 2012-08-08 13:56:54

+0

几个月前,他们没有工作......感谢澄清:)很高兴看到这个问题的简单方法 – paxRoman 2012-08-08 14:51:37

回答

61

text-anchor属性按预期在D3创建的svg元素上工作。但是,您需要将textcircle附加到常见的g元素中,以确保textcircle相互居中。

要做到这一点,您可以在nodes变量更改为:

var nodes = svg.append("g") 
      .attr("class", "nodes") 
      .selectAll("circle") 
      .data(dataset) 
      .enter() 
      // Add one g element for each data node here. 
      .append("g") 
      // Position the g element like the circle element used to be. 
      .attr("transform", function(d, i) { 
      // Set d.x and d.y here so that other elements can use it. d is 
      // expected to be an object here. 
      d.x = i * 70 + 50, 
      d.y = svg_h/2; 
      return "translate(" + d.x + "," + d.y + ")"; 
      }); 

注意,dataset现在是一个对象的列表,以便d.yd.x可以使用,而不是仅仅一个字符串列表。

然后,用下面的更换你的circletext追加代码:

// Add a circle element to the previously added g element. 
nodes.append("circle") 
     .attr("class", "node") 
     .attr("r", 20); 

// Add a text element to the previously added g element. 
nodes.append("text") 
    .attr("text-anchor", "middle") 
    .text(function(d) { 
     return d.name; 
     }); 

现在,而不是改变的位置circle如果改变了移动既circletextg元素的位置。

这里是一个JSFiddle显示圆圈上居中的文字。

如果您希望您的文字是在一个单独的g元素,使其始终在顶部出现,然后使用d.xd.y值在第一g元素的创作设置为transform文本。

var text = svg.append("svg:g").selectAll("g") 
     .data(force.nodes()) 
     .enter().append("svg:g"); 

text.append("svg:text") 
    .attr("text-anchor", "middle") 
    .text(function(d) { return d.name; }); 

text.attr("transform", function(d) { 
     return "translate(" + d.x + "," + d.y + ")"; 
    }); 
+0

感谢您的答案!看起来你的方法类似于[答案](http://stackoverflow.com/questions/11102795/d3-node-labeling/11109803#11109803)中概述的第一种方法,这意味着每个标签将被绘制*在其顶部仅限于其圆*,但将被绘制*在其他圆圈之下*。是否可以使用相同答案中概述的双数据连接方法来完成? (这是我模仿我的尝试)。谢谢! – skyork 2012-08-08 14:35:09

+0

我为此做了更新。你需要改变的两件事情是让你的数据成为一个对象列表而不是一串字符串,这样就可以为每个字符串存储'y'和'x',并将你的文本放在一个'g'元素中,这样'g'元素可以被转换。 – 2012-08-08 14:52:00

+0

如果我正确地理解了上面更新的代码,首先创建一个'g'元素,并在其中为数组中的数据创建一系列'g'元素,然后在这些''' g'元素?有什么让我困惑的是'text.append(“svg:text”)...',这里的'text'代表一系列'g'元素吗?如果是这样,D3如何为这些'g'元素*创建一个'text'元素?语法有点误导。 – skyork 2012-08-08 17:04:50

23

最佳答案came from the asker自己:

只是进一步的观察:只。attr(“text-anchor”,“middle”) 对于每个文本元素,标签位于水平中间,但是垂直略微偏离 。我通过添加attr(“y”,“.3em”) (从d3.js网站上的示例中借用)来解决此问题,即使对于任意大小的节点圆,似乎也能很好地运行 。然而,这个额外的属性究竟是怎么回避我的理解。当然,它确实对每个文本元素的y坐标有一些东西,但是为什么.3em在 特别是?对我来说这似乎很神奇...

只需将.attr("text-anchor", "middle")添加到每个文本元素。

例子:

node.append("text") 
    .attr("x", 0) 
    .attr("dy", ".35em") 
    .attr("text-anchor", "middle") 
    .text(function(d) { return d.name; }); 
+0

忽略选定的答案。这是一个更好的方法。 – Matt 2017-02-04 04:54:40

+0

哇。好事我滚动到下一个答案。我懒惰没有阅读所选择的答案。 – Martin 2017-03-22 04:57:34

+0

使用这个时,我的HTML有文本,但它并没有出现在我的实际节点中。 – 2017-12-16 06:20:54