我一直在使用这个 d3 项目中的示例代码来学习如何显示 d3 图形,但我似乎无法让文本显示在圆圈中间(类似于此示例和此示例)。我看过其他例子,并尝试添加
node.append("title").text("Node Name To Display")
和
node.append("text")
.attr("text-anchor", "middle")
.attr("dy", ".3em").text("Node Name To Display")
定义节点后,但我看到的唯一结果是当我将鼠标悬停在每个节点上时显示"要显示的节点名称"。它不会在圆圈内显示为文本。我是否必须编写自己的 svg 文本对象并根据圆的半径坐标确定需要放置它的坐标?从其他两个例子来看,d3似乎已经以某种方式解决了这个问题。我只是不知道调用/设置的正确属性。
有很多示例显示了如何向图形和树可视化添加标签,但我可能会从最简单的示例开始:
- http://bl.ocks.org/950642
您尚未发布指向代码的链接,但我猜node
指的是一系列 SVG 圆元素。不能向圆形元素添加文本元素,因为圆形元素不是容器;将忽略向圆圈添加文本元素。
通常,使用 G 元素对每个节点的圆形元素(或图像元素,如上所述)和文本元素进行分组。生成的结构如下所示:
<g class="node" transform="translate(130,492)">
<circle r="4.5"/>
<text dx="12" dy=".35em">Gavroche</text>
</g>
使用数据联接为每个节点创建 G 元素,然后使用 selection.append 为每个节点添加一个圆和一个文本元素。像这样:
var node = svg.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", 4.5);
node.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) { return d.name });
这种方法的一个缺点是您可能希望将标签绘制在圆圈的顶部。由于 SVG 尚不支持 z 索引,因此元素按文档顺序绘制;因此,上述方法会导致标签绘制在其圆圈上方,但可以在其他圆圈下绘制。您可以通过使用两个数据联接并为圆圈和标签创建单独的组来解决此问题,如下所示:
<g class="nodes">
<circle transform="translate(130,492)" r="4.5"/>
<circle transform="translate(110,249)" r="4.5"/>
…
</g>
<g class="labels">
<text transform="translate(130,492)" dx="12" dy=".35em">Gavroche</text>
<text transform="translate(110,249)" dx="12" dy=".35em">Valjean</text>
…
</g>
以及相应的 JavaScript:
var circle = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("r", 4.5)
.call(force.drag);
var text = svg.append("g")
.attr("class", "labels")
.selectAll("text")
.data(nodes)
.enter().append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) { return d.name });
此技术用于移动专利套装示例(使用用于创建白色阴影的附加文本元素)。
我发现本指南在尝试完成类似的事情时非常有用:
https://www.dashingd3js.com/svg-text-element
基于上面的链接,此代码将生成圆形标签:
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body style="overflow: hidden;">
<div id="canvas" style="overflow: hidden;"></div>
<script type="text/javascript">
var graph = {
"nodes": [
{name: "1", "group": 1, x: 100, y: 90, r: 10 , connected : "2"},
{name: "2", "group": 1, x: 200, y: 50, r: 15, connected : "1"},
{name: "3", "group": 2, x: 200, y: 130, r: 25, connected : "1"}
]
}
$( document ).ready(function() {
var width = 2000;
var height = 2000;
var svg = d3.select("#canvas").append("svg")
.attr("width", width)
.attr("height", height)
.append("g");
var lines = svg.attr("class", "line")
.selectAll("line").data(graph.nodes)
.enter().append("line")
.style("stroke", "gray") // <<<<< Add a color
.attr("x1", function (d, i) {
return d.x
})
.attr("y1", function (d) {
return d.y
})
.attr("x2", function (d) {
return findAttribute(d.connected).x
})
.attr("y2", function (d) {
return findAttribute(d.connected).y
})
var circles = svg.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.style("stroke", "gray")
.style("fill", "white")
.attr("r", function (d, i) {
return d.r
})
.attr("cx", function (d, i) {
return d.x
})
.attr("cy", function (d, i) {
return d.y
});
var text = svg.selectAll("text")
.data(graph.nodes)
.enter()
.append("text");
var textLabels = text
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.text( function (d) { return d.name })
.attr("font-family", "sans-serif")
.attr("font-size", "10px")
.attr("fill", "red");
});
function findAttribute(name) {
for (var i = 0, len = graph.nodes.length; i < len; i++) {
if (graph.nodes[i].name === name)
return graph.nodes[i]; // Return as soon as the object is found
}
return null; // The object was not found
}
</script>
</body>
</html>
如果要增大节点以适应大标签,可以在绘制 SVG 文本节点后使用它。以下是我的做法,用于具有固定坐标和两种可能形状的节点列表:
nodes.forEach(function(v) {
var nd;
var cx = v.coord[0];
var cy = v.coord[1];
switch (v.shape) {
case "circle":
nd = svg.append("circle");
break;
case "rectangle":
nd = svg.append("rect");
break;
}
var w = 10;
var h = 10;
if (v.label != "") {
var lText = svg.append("text");
lText.attr("x", cx)
.attr("y", cy + 5)
.attr("class", "labelText")
.text(v.label);
var bbox = lText.node().getBBox();
w = Math.max(w,bbox.width);
h = Math.max(h,bbox.height);
}
var pad = 4;
switch (v.shape) {
case "circle":
nd.attr("cx", cx)
.attr("cy", cy)
.attr("r", Math.sqrt(w*w + h*h)/2 + pad);
break;
case "rectangle":
nd.attr("x", cx - w/2 - pad)
.attr("y", cy - h/2 - pad)
.attr("width", w + 2*pad)
.attr("height", h + 2*pad);
break;
}
});
请注意,添加形状,添加文本,然后定位形状,以使文本显示在顶部。