Javascript 在 d3.js 中将标签放置在节点的中心
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11857615/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Placing labels at the center of nodes in d3.js
提问by skyork
I am starting with d3.js, and am trying to create a row of nodes each of which contains a centered number label.
我从 d3.js 开始,并试图创建一行节点,每个节点都包含一个居中的数字标签。
I am able to produce the desired result visually, but the way I did it is hardly optimal as it involves hard-coding the x-y coordinates for each text element. Below is the code:
我能够在视觉上产生所需的结果,但我这样做的方式几乎不是最佳的,因为它涉及对每个文本元素的 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;
});
The node
class is custom CSS class I've defined separately for the circle
elements, whereas classes nodes
and labels
are not explicitly defined and they are borrowed from this answer.
该node
班是我单独定义自定义CSS类circle
的元素,而班级nodes
和labels
没有被明确定义,他们是从这个借来的答案。
As seen, the positioning of each text label is hard-coded so that it appears at the center of the each node. Obviously, this is not the right solution.
正如所见,每个文本标签的位置都是硬编码的,因此它出现在每个节点的中心。显然,这不是正确的解决方案。
My question is that how should I correctly associate each text label with each node circle dynamically so that if the positioning of a label changes along with that of a circle automatically. Conceptual explanation is extremely welcome with code example.
我的问题是,我应该如何正确地将每个文本标签与每个节点圆圈动态关联,以便标签的位置与圆圈的位置一起自动更改。代码示例非常欢迎概念性解释。
回答by Brant Olsen
The text-anchorattribute works as expected on an svg element created by D3. However, you need to append the text
and the circle
into a common g
element to ensure that the text
and the circle
are centered with one another.
该文本锚属性的工作原理是D3创建的SVG元素如预期。但是,您需要将 thetext
和 the附加circle
到一个公共g
元素中,以确保 thetext
和 thecircle
彼此居中。
To do this, you can change your nodes
variable to:
为此,您可以将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 + ")";
});
Note that the dataset
is now a list of objects so that d.y
and d.x
can be used instead of just a list of strings.
请注意,dataset
现在是一个对象,这样的列表d.y
,并d.x
可以用来代替只是一个字符串列表中。
Then, replace your circle
and text
append code with the following:
然后,用以下内容替换您circle
和text
附加的代码:
// 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;
});
Now, instead of changing the position of the circle
you change the position of the g
element which moves both the circle
and the text
.
现在,不是更改 的位置,而是更改同时移动和 的元素circle
的位置。g
circle
text
Here is a JSFiddleshowing centered text on circles.
这是一个在圆圈上显示居中文本的JSFiddle。
If you want to have your text be in a separate g
element so that it always appears on top, then use the d.x
and d.y
values set in the first g
element's creation to transform
the text.
如果你想让你的文本在一个单独的g
元素中,以便它总是出现在顶部,那么使用d.x
和d.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 + ")";
});
回答by tacone
The best answer came from the askerhimself:
最佳答案来自提问者本人:
just a further observation: with only .attr("text-anchor", "middle") for each text element, the label is at the middle horizontally but slightly off vertically. I fixed this by adding attr("y", ".3em") (borrowed from examples at d3.js website), which seems to work well even for arbitrary size of node circle. However, what exactly this additional attribute does eludes my understanding. Sure, it does something to the y-coordinate of each text element, but why .3em in particular? It seems almost magical to me...
只是进一步观察:每个文本元素只有 .attr("text-anchor", "middle") ,标签位于水平中间但垂直略微偏离。我通过添加 attr("y", ".3em") (从 d3.js 网站的示例中借用)解决了这个问题,即使对于任意大小的节点圆,它似乎也能很好地工作。然而,这个附加属性究竟有什么作用,我无法理解。当然,它对每个文本元素的 y 坐标做了一些事情,但为什么特别是 .3em?对我来说这几乎是神奇的......
Just add .attr("text-anchor", "middle")
to each text element.
只需添加.attr("text-anchor", "middle")
到每个文本元素。
Example:
例子:
node.append("text")
.attr("x", 0)
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d) { return d.name; });
回答by MichaelGreene
This page describes what's going on under the svg hoodwhen it comes to text elements. Understanding the underlying machinery and data structures helped me get a better handle on how I had to modify my code to get it working.
这个页面描述了当涉及到文本元素时svg 引擎盖下发生了什么。了解底层机制和数据结构帮助我更好地了解如何修改代码才能使其正常工作。