在StreamGraph中包装标签

时间:2017-08-21 23:47:57

标签: javascript d3.js svg

我正在尝试包装宽度大于10px的标签。为此,我使用了Bostock的wrap function

我在我的代码中使用了wrap函数,并通过传递标签来调用它,例如“titanic eva mission impossible”。但是,标签彼此重叠,而不是每个单词以分开的行分开。

我的项目在这里:StreamGraph With AreaLabel

<!doctype html>              

<html>    
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.8/d3.min.js" type="text/JavaScript"></script>
<script src="https://unpkg.com/d3-area-label@1.2.0"></script>

<style>
  body {
    margin: 0px;
  }
  .area-label {
    font-family: sans-serif;
    height: 20;
    width: auto;
    fill-opacity: 0.7;
    fill: white;
  }
  path:hover {
    fill-opacity: 1;
    fill:black;
  }
  path {
    fill-opacity: 0.8;
    stroke-width: 0.5;
  }
  text {
    pointer-events: none;
  }
</style>
</head>
<body>
<div id="viz">
  <svg style="width:960px;height:500px;" ></svg>

</div>

<script>

  d3.csv("movies.csv", dataViz);

  function dataViz(data) 
{
    var xScale = d3.scaleLinear().domain([0, 10]).range([0, 960]);
    var yScale = d3.scaleLinear().domain([0, 100]).range([500, 0]);

    var movies = ["titanic eva mission impossible", "avatar", "akira", "frozen", "deliverance", "avengers"];

    var fillScale = d3.scaleOrdinal().domain(movies)
      .range(["#fcd88a", "#cf7c1c", "#93c464", "#75734F", "#5eafc6", "#41a368"]);

    stacked = d3.stack()
                .offset(d3.stackOffsetSilhouette)
                .order(d3.stackOrderInsideOut)
                .keys(movies);

    yScale.domain([-50, 50]);

    var xValue = function (d) { return d.day; };

    var stackArea = d3.area()
      .x(d => xScale(xValue(d.data)))
      .y0(d => yScale(d[0]))
      .y1(d => yScale(d[1]))
      .curve(d3.curveBasis);

    d3.select("svg")
        .selectAll("path").data(stacked(data)).enter().append("path")
        .style("fill", d => fillScale(d.key))
        .attr("d", d => stackArea(d));

    labels = d3.select("svg")
               .selectAll('text').data(stacked(data))
    labels
    .enter().append("g")
    .append('text')
    .attr('class', 'area-label')
    .text(d => d.key)
    .attr('transform',
      d3.areaLabel(stackArea).interpolateResolution(1000).interpolate(true));

    d3.select("svg").select("g").select("text").call(wrap,10);
}
    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", ++lineNumber * lineHeight + dy + "em").text(word);
          }
        }
      });
    } 
</script>

1 个答案:

答案 0 :(得分:0)

只需设置ydy属性:

labels.enter().append("g")
    .append('text')
    .attr("y", 0)
    .attr("dy", 0)
    //etc...

这是您更新的代码:

&#13;
&#13;
var movies = `day,titanic eva mission impossible,avatar,akira,frozen,deliverance,avengers
1,40,8,10,0,0,0
2,18,5,1,13,0,0
3,14,3,1,10,0,0
4,7,3,0,5,27,15
5,4,3,0,2,20,14
6,3,1,0,0,10,13
7,2,0,0,0,8,12
8,0,0,0,0,6,11
9,0,0,0,0,3,9
10,0,0,0,0,1,8`;

var data = d3.csvParse(movies);

dataViz(data);

function dataViz(data) {
  var xScale = d3.scaleLinear().domain([0, 10]).range([0, 960]);
  var yScale = d3.scaleLinear().domain([0, 100]).range([500, 0]);

  var movies = ["titanic eva mission impossible", "avatar", "akira", "frozen", "deliverance", "avengers"];

  var fillScale = d3.scaleOrdinal().domain(movies)
    .range(["#fcd88a", "#cf7c1c", "#93c464", "#75734F", "#5eafc6", "#41a368"]);

  stacked = d3.stack()
    .offset(d3.stackOffsetSilhouette)
    .order(d3.stackOrderInsideOut)
    .keys(movies);

  yScale.domain([-50, 50]);

  var xValue = function(d) {
    return d.day;
  };

  var stackArea = d3.area()
    .x(d => xScale(xValue(d.data)))
    .y0(d => yScale(d[0]))
    .y1(d => yScale(d[1]))
    .curve(d3.curveBasis);

  d3.select("svg")
    .selectAll("path").data(stacked(data)).enter().append("path")
    .style("fill", d => fillScale(d.key))
    .attr("d", d => stackArea(d));

  labels = d3.select("svg")
    .selectAll('text').data(stacked(data))
  labels.enter().append("g")
    .append('text')
    .attr("y", 0)
    .attr("dy", 0)
    .attr('class', 'area-label')
    .text(d => d.key)
    .attr('transform', d3.areaLabel(stackArea).interpolateResolution(1000).interpolate(true));

  d3.select("svg").select("g").select("text").call(wrap, 10);
}

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", ++lineNumber * lineHeight + dy + "em").text(word);
      }
    }
  });
}
&#13;
body {
  margin: 0px;
}

.area-label {
  font-family: sans-serif;
  height: 20;
  width: auto;
  fill-opacity: 0.7;
  fill: white;
}

path:hover {
  fill-opacity: 1;
  fill: black;
}

path {
  fill-opacity: 0.8;
  stroke-width: 0.5;
}

text {
  pointer-events: none;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.8/d3.min.js" type="text/JavaScript"></script>
<script src="https://unpkg.com/d3-area-label@1.2.0"></script>
<div id="viz">
  <svg style="width:960px;height:500px;"></svg>
</div>
&#13;
&#13;
&#13;

PS:d3-area-label将文本定位在路径的垂直中心。但是,您必须将其向上移动一点,以避免文本与下面的路径重叠。