在 D3 力导向图中的节点上垂直居中由多条线组成的标签
Vertically center a label consisting of multiple lines over a node in D3 force directed graph
我有一个 D3 力导向图,每个节点都显示一个标签。此标签的长度可以从单行文本到多行文本不等。参考这个post,我已经成功地为节点创建了一个多行标签。但是,我想将标签垂直居中放置在节点上。我无法以一种对所有标签类型(例如单行标签、两行标签等)都有效的方式将标签位置重新分配到垂直中心。
基本上,我不确定如何将标签作为一个整体居中,同时保持标签中每行文本之间的分隔。如有任何帮助,我们将不胜感激。
var node = svg.selectAll('.node')
.data(force.nodes())
.enter().append('circle')
.attr('class', 'node')
.attr('r', width * 0.01)
.style('fill', function(d) {return color(d.group); })
var maxLength = 20;
var separation = 12;
var textX = 0;
var text = svg.selectAll(".text")
.data(nodes)
.enter().append("text")
.style("text-anchor", "middle")
.each(function (d) {
var lines = wordwrap2(d.name, maxLength).split('\n');
for (var i = 0; i < lines.length; i++) {
d3.select(this)
.append("tspan")
.attr("dy", separation)
.attr("x", textX)
.text(lines[i]);
}});
function wordwrap2( str, width, brk, cut ) {
brk = brk || '\n';
width = width || 75;
cut = cut || false;
if (!str) { return str; }
var regex = '.{0,' +width+ '}(\s|$)' + (cut ? '|.{' +width+ '}|.+$' : '|\S+?(\s|$)');
return str.match( RegExp(regex, 'g') ).join( brk );
};
Select 标签并将其平移一半高度,使用 lines.length
和 separation
:
d3.select(this).attr("transform", "translate(0," + (separation*lines.length/2*-1) + ")");
这是一个演示:
<script src="https://d3js.org/d3.v2.min.js?2.9.3"></script>
<style>
.link {
stroke: #aaa;
}
.node text {
stroke: #333;
cursor: pointer;
}
.node circle {
stroke: #fff;
stroke-width: 3px;
fill: #555;
}
</style>
<body>
<script>
var width = 400,
height = 300
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.distance(50)
.charge(-3000)
.size([width, height]);
var json = {
"nodes": [{
"name": "node1"
}, {
"name": "node2"
}, {
"name": "node3"
}, {
"name": "node4"
}, {
"name": "node5 has a very very very very long long name"
}],
"links": [{
"source": 0,
"target": 1
}, {
"source": 0,
"target": 2
}, {
"source": 0,
"target": 3
}, {
"source": 0,
"target": 4
}]
};
force
.nodes(json.nodes)
.links(json.links)
.start();
var link = svg.selectAll(".link")
.data(json.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", 2);
var node = svg.selectAll(".node")
.data(json.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", 8);
var maxLength = 10;
var separation = 12;
var textX = 0;
node.append("text")
.attr("dominant-baseline", "central")
.attr("dx", 12)
.attr("dy", ".35em")
.each(function (d) {
var lines = wordwrap2(d.name, maxLength).split('\n');
for (var i = 0; i < lines.length; i++) {
d3.select(this)
.append("tspan")
.attr("dy", separation)
.attr("x", textX)
.text(lines[i]);
d3.select(this).attr("transform", "translate(0," + (separation*lines.length/2*-1) + ")");
}});
function wordwrap2( str, width, brk, cut ) {
brk = brk || '\n';
width = width || 75;
cut = cut || false;
if (!str) { return str; }
var regex = '.{0,' +width+ '}(\s|$)' + (cut ? '|.{' +width+ '}|.+$' : '|\S+?(\s|$)');
return str.match( RegExp(regex, 'g') ).join( brk );
};
force.on("tick", function() {
link.attr("x1", function(d) {
return d.source.x;
})
.attr("y1", function(d) {
return d.source.y;
})
.attr("x2", function(d) {
return d.target.x;
})
.attr("y2", function(d) {
return d.target.y;
});
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
});
</script>
我有一个 D3 力导向图,每个节点都显示一个标签。此标签的长度可以从单行文本到多行文本不等。参考这个post,我已经成功地为节点创建了一个多行标签。但是,我想将标签垂直居中放置在节点上。我无法以一种对所有标签类型(例如单行标签、两行标签等)都有效的方式将标签位置重新分配到垂直中心。
基本上,我不确定如何将标签作为一个整体居中,同时保持标签中每行文本之间的分隔。如有任何帮助,我们将不胜感激。
var node = svg.selectAll('.node')
.data(force.nodes())
.enter().append('circle')
.attr('class', 'node')
.attr('r', width * 0.01)
.style('fill', function(d) {return color(d.group); })
var maxLength = 20;
var separation = 12;
var textX = 0;
var text = svg.selectAll(".text")
.data(nodes)
.enter().append("text")
.style("text-anchor", "middle")
.each(function (d) {
var lines = wordwrap2(d.name, maxLength).split('\n');
for (var i = 0; i < lines.length; i++) {
d3.select(this)
.append("tspan")
.attr("dy", separation)
.attr("x", textX)
.text(lines[i]);
}});
function wordwrap2( str, width, brk, cut ) {
brk = brk || '\n';
width = width || 75;
cut = cut || false;
if (!str) { return str; }
var regex = '.{0,' +width+ '}(\s|$)' + (cut ? '|.{' +width+ '}|.+$' : '|\S+?(\s|$)');
return str.match( RegExp(regex, 'g') ).join( brk );
};
Select 标签并将其平移一半高度,使用 lines.length
和 separation
:
d3.select(this).attr("transform", "translate(0," + (separation*lines.length/2*-1) + ")");
这是一个演示:
<script src="https://d3js.org/d3.v2.min.js?2.9.3"></script>
<style>
.link {
stroke: #aaa;
}
.node text {
stroke: #333;
cursor: pointer;
}
.node circle {
stroke: #fff;
stroke-width: 3px;
fill: #555;
}
</style>
<body>
<script>
var width = 400,
height = 300
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.distance(50)
.charge(-3000)
.size([width, height]);
var json = {
"nodes": [{
"name": "node1"
}, {
"name": "node2"
}, {
"name": "node3"
}, {
"name": "node4"
}, {
"name": "node5 has a very very very very long long name"
}],
"links": [{
"source": 0,
"target": 1
}, {
"source": 0,
"target": 2
}, {
"source": 0,
"target": 3
}, {
"source": 0,
"target": 4
}]
};
force
.nodes(json.nodes)
.links(json.links)
.start();
var link = svg.selectAll(".link")
.data(json.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", 2);
var node = svg.selectAll(".node")
.data(json.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", 8);
var maxLength = 10;
var separation = 12;
var textX = 0;
node.append("text")
.attr("dominant-baseline", "central")
.attr("dx", 12)
.attr("dy", ".35em")
.each(function (d) {
var lines = wordwrap2(d.name, maxLength).split('\n');
for (var i = 0; i < lines.length; i++) {
d3.select(this)
.append("tspan")
.attr("dy", separation)
.attr("x", textX)
.text(lines[i]);
d3.select(this).attr("transform", "translate(0," + (separation*lines.length/2*-1) + ")");
}});
function wordwrap2( str, width, brk, cut ) {
brk = brk || '\n';
width = width || 75;
cut = cut || false;
if (!str) { return str; }
var regex = '.{0,' +width+ '}(\s|$)' + (cut ? '|.{' +width+ '}|.+$' : '|\S+?(\s|$)');
return str.match( RegExp(regex, 'g') ).join( brk );
};
force.on("tick", function() {
link.attr("x1", function(d) {
return d.source.x;
})
.attr("y1", function(d) {
return d.source.y;
})
.attr("x2", function(d) {
return d.target.x;
})
.attr("y2", function(d) {
return d.target.y;
});
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
});
</script>