将标签放置在d3.js中的节点的中心

我从d3.js开始,尝试创build一个包含居中号码标签的节点行。

我能够在视觉上产生所需的结果,但是我所做的方式并不是最佳的,因为它涉及硬编码每个文本元素的xy坐标。 以下是代码:

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类是自定义的CSS类,我已经为circle元素单独定义,而类nodeslabels没有明确定义,它们是从这个答案借来的。

如所看到的,每个文本标签的定位是硬编码的,以便它出现在每个节点的中心。 显然,这不是正确的解决scheme。

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

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

要做到这一点,你可以改变你的nodesvariables为:

 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 dx and dy here so that other elements can use it. d is // expected to be an object here. dx = i * 70 + 50, dy = svg_h / 2; return "translate(" + dx + "," + dy + ")"; }); 

请注意, dataset现在是对象列表,因此可以使用dydx而不是仅使用一个string列表。

然后,replace你的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元素中,以便始终显示在顶部,则使用在第一个g元素的创build中设置的dxdy值来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(" + dx + "," + dy + ")"; }); 

最好的答案来自提问者自己:

只是进一步的观察:对于每个文本元素只有.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; }); 

这个页面描述了svg引擎在文本元素下发生了什么 。 了解底层的机器和数据结构帮助我更好地处理了如何修改代码以使其工作。