我想让文本包装在以下D3树上,而不是
- Foo is not a long word
每条线都被包裹起来
- Foo is
- not a
- long word
我已经尝试使文本为“foreignObject”而不是文本对象,文本确实包含,但它不会在树动画上移动,并且都分组在左上角.
代码位于
http://jsfiddle.net/mikeyai/X43X5/1/
使用Javascript:
- var width = 960,height = 500;
- var tree = d3.layout.tree()
- .size([width - 20,height - 20]);
- var root = {},nodes = tree(root);
- root.parent = root;
- root.px = root.x;
- root.py = root.y;
- var diagonal = d3.svg.diagonal();
- var svg = d3.select("body").append("svg")
- .attr("width",width)
- .attr("height",height)
- .append("g")
- .attr("transform","translate(10,10)");
- var node = svg.selectAll(".node"),link = svg.selectAll(".link");
- var duration = 750,timer = setInterval(update,duration);
- function update() {
- if (nodes.length >= 500) return clearInterval(timer);
- // Add a new node to a random parent.
- var n = {id: nodes.length},p = nodes[Math.random() * nodes.length | 0];
- if (p.children) p.children.push(n); else p.children = [n];
- nodes.push(n);
- // Recompute the layout and data join.
- node = node.data(tree.nodes(root),function(d) { return d.id; });
- link = link.data(tree.links(nodes),function(d) { return d.source.id + "-" + d.target.id; });
- // Add entering nodes in the parent’s old position.
- node.enter().append("text")
- .attr("class","node")
- .attr("x",function(d) { return d.parent.px; })
- .attr("y",function(d) { return d.parent.py; })
- .text('Foo is not a long word');
- // Add entering links in the parent’s old position.
- link.enter().insert("path",".node")
- .attr("class","link")
- .attr("d",function(d) {
- var o = {x: d.source.px,y: d.source.py};
- return diagonal({source: o,target: o});
- });
- // Transition nodes and links to their new positions.
- var t = svg.transition()
- .duration(duration);
- t.selectAll(".link")
- .attr("d",diagonal);
- t.selectAll(".node")
- .attr("x",function(d) { return d.px = d.x; })
- .attr("y",function(d) { return d.py = d.y; });
- }
解决方法
您可以修改
Mike Bostock’s “Wrapping Long Labels” example以添加< tspan>元素到您的< text>节点.将包装文本添加到您的节点需要两个主要更改.我没有深入了解文本在过渡期间更新其位置,但不应该太难添加.
第一个是在上面的例子中添加一个基于函数的函数换行符. wrap将负责添加< tspan>元素使您的文字适合一定宽度:
- function wrap(text,width) {
- text.each(function () {
- var text = d3.select(this),words = "Foo is not a long word".split(/\s+/).reverse(),word,line = [],lineNumber = 0,lineHeight = 1.1,// ems
- x = text.attr("x"),y = text.attr("y"),dy = 0,//parseFloat(text.attr("dy")),tspan = text.text(null)
- .append("tspan")
- .attr("x",x)
- .attr("y",y)
- .attr("dy",dy + "em");
- while (word = words.pop()) {
- line.push(word);
- tspan.text(line.join(" "));
- if (tspan.node().getComputedTextLength() > width) {
- line.pop();
- tspan.text(line.join(" "));
- line = [word];
- tspan = text.append("tspan")
- .attr("x",x)
- .attr("y",y)
- .attr("dy",++lineNumber * lineHeight + dy + "em")
- .text(word);
- }
- }
- });
- }
第二个变化是,不需要设置每个节点的文本,您需要为每个节点调用换行符:
- // Add entering nodes in the parent’s old position.
- node.enter().append("text")
- .attr("class","node")
- .attr("x",function (d) { return d.parent.px; })
- .attr("y",function (d) { return d.parent.py; })
- .call(wrap,30); // wrap the text in <= 30 pixels