javascript - D3垂直条形图为标签文本添加换行符

标签 javascript d3.js charts bar-chart

我试图打破 y 轴标签的长线。我的条形图就像 this但标签较长(通常超过 10 个带有空格的单词)。这是我的代码(它有效,我看到了图表,唯一的“错误”是文本,我动态加载 JSON,此数据仅适用于 SO):

HTML:

<svg id='table1'></svg>

<script>
    var window_width = $(window).width();
    var main_width = (window_width / 100 ) * 80;
    var w = main_width - 400;

    var data = {
      labels: [
        'the text to be splitted 1', 'the text to be splitted 2'
      ],
      series: [
        {
          label: '2012',
          values: [4, 8]
        },
        {
          label: '2013',
          values: [12, 43]
        }
      ]
    };

    var chartWidth   = w,
    barHeight        = 25,
    groupHeight      = barHeight * data.series.length,
    gapBetweenGroups = 10,
    spaceForLabels   = 175,
    spaceForLegend   = 0;

    // Zip the series data together (first values, second values, etc.)
    var zippedData = [];
    for (var i=0; i<data.labels.length; i++) {
      for (var j=0; j<data.series.length; j++) {
        zippedData.push(data.series[j].values[i]);
      }
    }

    var chartHeight = barHeight * zippedData.length + gapBetweenGroups * data.labels.length;
    var x = d3.scale.linear()
        .domain([0, d3.max(zippedData)])
        .range([0, chartWidth]);

    var y = d3.scale.linear()
        .range([chartHeight + gapBetweenGroups, 0]);

    var yAxis = d3.svg.axis()
        .scale(y)
        .tickFormat('')
        .tickSize(0)
        .orient("left");

    // Specify the chart area and dimensions
    var chart = d3.select("#table"+ambit)
        .attr("width", spaceForLabels + chartWidth + spaceForLegend)
        .attr("height", chartHeight);

    // Create bars
    var bar = chart.selectAll("g")
        .data(zippedData)
        .enter().append("g")
        .attr("transform", function(d, i) {
          return "translate(" + spaceForLabels + "," + (i * barHeight + gapBetweenGroups * (0.5 + Math.floor(i/data.series.length))) + ")";
        });

    // Create rectangles of the correct width
    bar.append("rect")
        .attr("fill", function(d,i) { return color(i % data.series.length); })
        .attr("class", "bar")
        .attr("width", x)
        .attr("height", barHeight - 1);

    // Add text label in bar
    bar.append("text")
        .attr("class", "label_txt1")    
        .attr("x", function(d) { return x(d) - 3; })
        .attr("y", barHeight / 2)
        .attr("fill", "red")
        .attr("dy", ".35em")
        .text(function(d) { return d; });

    // Draw labels
    bar.append("text")
        .attr("class", "label_txt")
        .attr("x", function(d) { return - 10; })
        .attr("y", groupHeight / 2)
        .attr("dy", ".35em")
        .text(function(d,i) {
          if (i % data.series.length === 0)
        return data.labels[Math.floor(i/data.series.length)];
          else
        return ""});

    chart.append("g")
          .attr("class", "y axis")
          .attr("transform", "translate(" + spaceForLabels + ", " + -gapBetweenGroups/2 + ")")
          .call(yAxis);

</script>

我遵循多个示例来解决此问题,例如: How do I include newlines in labels in D3 charts?Adding a line break to D3 graph y-axis labelsWrapping Long Labels .

第一次尝试:

var insertLinebreaks = function (d) {
    var el = d3.select(this);
    var words = d.split(' ');
    el.text('');

    for (var i = 0; i < words.length; i++) {
    var tspan = el.append('tspan').text(words[i]);
    if (i > 0)
        tspan.attr('x', 0).attr('dy', '15');
    }
};

chart.selectAll('g.y.axis text').each(insertLinebreaks); 

和:

bar.selectAll('.label_txt1').each(insertLinebreaks);

我也尝试过:

bar.append("text")
    .attr("class", "label_txt1")    
    .attr("x", function(d) { return x(d) - 3; })
    .attr("y", barHeight / 2)
    .attr("fill", "red")
    .attr("dy", ".35em")
    .text(function(d) { return d; });

chart.selectAll(".label_txt1").call(wrap, 40)

function wrap(text, width) {
    alert(JSON.stringify(text));
    text.each(function() {
        var text = d3.select(this),
        words = text.text().split(/\s+/).reverse(),
        word,
        line = [],
        lineNumber = 0,
        y = text.attr("y"),
        dy = parseFloat(text.attr("dy")),
        lineHeight = 1.1, // ems
        tspan = text.text(null).append("tspan").attr("x", function(d) { return d.children || d._children ? -10 : 10; }).attr("y", y).attr("dy", dy + "em");     
        while (word = words.pop()) {
            line.push(word);
            tspan.text(line.join(" "));
            var textWidth = tspan.node().getComputedTextLength();
            if (tspan.node().getComputedTextLength() > width) {
                line.pop();
                tspan.text(line.join(" "));
                line = [word];
                ++lineNumber;
                tspan = text.append("tspan").attr("x", function(d) { return d.children || d._children ? -10 : 10; }).attr("y", 0).attr("dy", lineNumber * lineHeight + dy + "em").text(word);
            }
        }
    });
}

我改变了text()html()正如我读到的:How do I include newlines in labels in D3 charts?

在浏览器中我看到 <text>使用类 label_txt1 创建。当我尝试使用 selectAll(".label_txt1") 选择文本时我得到的是行的值,而不是文本。

有人可以帮助我吗?

最佳答案

这个example您引用的是使用 svg 文本节点时进行换行的规范方法。您只是将其称为错误的(在错误的类上,您正在包装数字)。将其简化为:

// Draw labels
bar.append("text")
  .attr("class", "label_txt")
  .attr("x", function(d) {
    return -10;
  })
  .attr("y", groupHeight / 2) //<-- not sure you need this
  .attr("dy", ".35em")
  .text(function(d, i) {
    if (i % data.series.length === 0)
      return data.labels[Math.floor(i / data.series.length)];
    else
      return ""
  })
  .call(wrap, 40);
<小时/>

完整代码:

<!DOCTYPE html>
<html>

<head>
  <script data-require="d3@3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
</head>

<body>
  <svg id="table1"></svg>
  <script>
    var window_width = 1000;
    var main_width = 400;
    var w = 400;

    var data = {
      labels: [
        'the text to be splitted 1', 'the text to be splitted 2'
      ],
      series: [{
        label: '2012',
        values: [4, 8]
      }, {
        label: '2013',
        values: [12, 43]
      }]
    };

    var chartWidth = w,
      barHeight = 25,
      groupHeight = barHeight * data.series.length,
      gapBetweenGroups = 10,
      spaceForLabels = 175,
      spaceForLegend = 0;

    var color = d3.scale.category10();

    // Zip the series data together (first values, second values, etc.)
    var zippedData = [];
    for (var i = 0; i < data.labels.length; i++) {
      for (var j = 0; j < data.series.length; j++) {
        zippedData.push(data.series[j].values[i]);
      }
    }

    var chartHeight = barHeight * zippedData.length + gapBetweenGroups * data.labels.length;
    var x = d3.scale.linear()
      .domain([0, d3.max(zippedData)])
      .range([0, chartWidth]);

    var y = d3.scale.linear()
      .range([chartHeight + gapBetweenGroups, 0]);

    var yAxis = d3.svg.axis()
      .scale(y)
      .tickFormat('')
      .tickSize(0)
      .orient("left");

    // Specify the chart area and dimensions
    var chart = d3.select("#table1")
      .attr("width", spaceForLabels + chartWidth + spaceForLegend)
      .attr("height", chartHeight);

    // Create bars
    var bar = chart.selectAll("g")
      .data(zippedData)
      .enter().append("g")
      .attr("transform", function(d, i) {
        return "translate(" + spaceForLabels + "," + (i * barHeight + gapBetweenGroups * (0.5 + Math.floor(i / data.series.length))) + ")";
      });

    // Create rectangles of the correct width
    bar.append("rect")
      .attr("fill", function(d, i) {
        return color(i % data.series.length);
      })
      .attr("class", "bar")
      .attr("width", x)
      .attr("height", barHeight - 1);

    // Add text label in bar
    bar.append("text")
      .attr("class", "label_txt1")
      .attr("x", function(d) {
        return x(d) - 3;
      })
      .attr("y", barHeight / 2)
      .attr("fill", "red")
      .attr("dy", ".35em")
      .text(function(d) {
        return d;
      });

    // Draw labels
    bar.append("text")
      .attr("class", "label_txt")
      .attr("x", function(d) {
        return -10;
      })
      //.attr("y", groupHeight / 2) //<-- you don't need this...
      .attr("dy", ".35em")
      .text(function(d, i) {
        if (i % data.series.length === 0)
          return data.labels[Math.floor(i / data.series.length)];
        else
          return ""
      })
      .call(wrap, 40);

    function wrap(text, width) {
      text.each(function() {
        var text = d3.select(this),
          words = text.text().split(/\s+/).reverse(),
          word,
          line = [],
          lineNumber = 0,
          y = text.attr("y"),
          dy = parseFloat(text.attr("dy")),
          lineHeight = 1.1, // ems
          tspan = text.text(null).append("tspan").attr("x", function(d) {
            return d.children || d._children ? -10 : 10;
          }).attr("y", y).attr("dy", dy + "em");
        while (word = words.pop()) {
          line.push(word);
          tspan.text(line.join(" "));
          var textWidth = tspan.node().getComputedTextLength();
          if (tspan.node().getComputedTextLength() > width) {
            line.pop();
            tspan.text(line.join(" "));
            line = [word];
            ++lineNumber;
            tspan = text.append("tspan").attr("x", function(d) {
              return d.children || d._children ? -10 : 10;
            }).attr("y", 0).attr("dy", lineNumber * lineHeight + dy + "em").text(word);
          }
        }
      });
    }

    chart.append("g")
      .attr("class", "y axis")
      .attr("transform", "translate(" + spaceForLabels + ", " + -gapBetweenGroups / 2 + ")")
      .call(yAxis);
  </script>
</body>

</html>

关于javascript - D3垂直条形图为标签文本添加换行符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36066183/

相关文章:

d3.js - 使用比例绘制网格或矩形

javascript - 如何将变量带入 d3 中的 .each 方法的范围

javascript - D3 在转换后启用鼠标悬停

charts - Flutter图表PanAndZoomBehavior不放大手势中心

javascript - 如何编写正则表达式来检查 JavaScript 中有效的 XML 元素 NCName?

javascript - 在 Chrome 扩展中使用 React js

javascript - 使用页面加载时图像的名称更新隐藏的输入字段

javascript - window.print() 是否适用于 iPad 上所有版本的 Safari?

charts - dimple.js 图表中图表和轴的标题

javascript - 如何在图表js中将x轴标签最小化为一天的时间