如何在D3.js中垂直包装SVG文本?

6

我使用D3还没有完全找到答案。我正在从SVG元素制作一个矩形工具提示,在单击节点时显示在图表上。当前,与工具提示相关联的文本(来自图表的JSON)仅水平扩展,即使工具提示的尺寸垂直扩展。考虑到矩形的固定宽度,我希望矩形在垂直方向上环绕文本换行,而不是水平方向。

以下是我单击节点时创建工具提示的位置:

nodes.on("click", function (d){
    if (tip){ tip.remove()};

    tip = svg.append("g")
        .attr("id", "tip")
        .attr("transform", "translate(" + (d3.event.pageX - 10)  + "," + (d3.event.pageY - 35) + ")");

    let rect = tip.append("rect")
        .style("fill", "white")
        .style("stroke", "steelblue");

    tip.append("text")
        .text(d.description)
        .attr("dy", "1em")
        .attr("x", 5);

    let bbox = tip.node().getBBox();

    rect.attr("width", bbox.width + 5)
        .attr("height", bbox.height)
});

这里有一个具备当前功能的jsfiddle演示:https://jsfiddle.net/Thegreatmochi/epy6514t/14/


为了能够做到这一点,您需要像此答案中所示将 <tspan> 添加到文本中:https://dev59.com/B2Qn5IYBdhLWcg3wn4NS - enxaneta
1个回答

3

您可以从这个bl.ocks.org链接中使用wrap函数,并进行微小的修改:

function wrap(text, width) {
  text.each(function() {
    var text = d3.select(this),
        words = text.text().split(/\s+/).reverse(),
        word,
        line = [],
        lineNumber = 0,
        lineHeight = 1.1, // ems
        y = text.attr("y"),
        dy = parseFloat(text.attr("dy")),
        tspan = text.text(null).append("tspan").attr("x", 0).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", 0).attr("y", y).attr("dy", lineHeight + "em").text(word);
      }
    }
  });
}

这里是一个可工作的代码片段:

let graph = {
  "nodes": [{
    "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed porta consequat felis, eget varius mi volutpat sit amet. Nullam lobortis vehicula felis, in tempor dui. Sed scelerisque purus ac nisl auctor finibus sit amet nec massa. Duis erat sem, suscipit non molestie vitae, accumsan nec tortor. Nulla sed facilisis ligula, nec interdum elit. Nam tortor lectus, sodales ut nulla ac, feugiat ultrices velit. Vestibulum nec ultricies nisi. Donec leo nibh, fringilla eget pretium nec, condimentum in nulla."
  }]
}

let svg = d3.select("body")
  .append("svg")
  .attr("width", 700)
  .attr("height", 800);

let nodes = svg.selectAll("circle")
  .data(graph.nodes)
  .enter()
  .append("circle")
  .attr("r", 20)
  .attr("cx", function(d) {
    return 20;
  })
  .attr("cy", function(d) {
    return 20;
  })
  .style("fill", "red");
let tip;
nodes.on("click", function(d) {
  if (tip) {
    tip.remove()
  };

  tip = svg.append("g")
    .attr("id", "tip")
    .attr("transform", "translate(" + (d3.event.pageX - 10) + "," + (d3.event.pageY - 35) + ")");

  let rect = tip.append("rect")
    .style("fill", "white")
    .style("stroke", "steelblue");

  tip.append("text")
    .text(d.description)
    .attr("dy", "1em")
    .attr("x", 5)
    .call(wrap, 300)

  let bbox = tip.node().getBBox();

  rect.attr("width", bbox.width + 5)
    .attr("height", bbox.height + 50)

});


function wrap(text, width) {
  text.each(function() {
    var text = d3.select(this),
      words = text.text().split(/\s+/).reverse(),
      word,
      line = [],
      lineNumber = 0,
      lineHeight = 1.1, // ems
      y = text.attr("y"),
      dy = parseFloat(text.attr("dy")),
      tspan = text.text(null).append("tspan").attr("x", 0).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", 0).attr("y", y).attr("dy", lineHeight + "em").text(word);
      }
    }
  });
}
<p>
  click the node to show description
</p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.12.2/d3.js"></script>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接