如何在D3中水平居中(响应)多行图例

时间:2018-03-23 16:51:39

标签: d3.js

我正在构建一个传奇,以便在D3 v4中创建的圆环图表中使用。到目前为止,我已设法添加彩色框和文本,图例将包装到容器中。

图例位于中心,但其中的项目目前为left-aligned。我希望它们在图表中居中,如thisthis(在调整大小时,取决于容器宽度)。还有一个奇怪的问题,第一个图例项目在调整大小/重绘时会消失。

由于我是D3的完全新手,我非常依赖现有的例子,而且我还没能找到任何类似于我想要实现的东西。我已使用this plunker作为图表的基础,this block作为图例包装代码。

这是我的传奇代码(完整的jsfiddle here):



var legendRectSize = 18;
var legendSpacing = 4;

var legendWrap = svg.append('g')
  .attr('class', 'legendwrap');

var legend = svg.select('.legendwrap').selectAll('.legend')
  .data(color.domain())
  .enter()
  .append('g')
  .attr('class', 'legend');

legend.append('rect')
  .attr('width', legendRectSize)
  .attr('height', legendRectSize)
  .style('fill', color)
  .style('stroke', color);

legend.append('text')
  .attr('x', legendRectSize + legendSpacing * 1.5)
  .attr('y', legendRectSize - legendSpacing)
  .text(function(d) {
    return d;
  });

var ypos = 0,
  newxpos = 0,
  maxwidth = 0,
  xpos;

legend
  .attr("transform", function(d, i) {
    var length = d3.select(this).select("text").node().getComputedTextLength() + 40;
    xpos = newxpos;
    if (width < xpos + length + 0) {
      newxpos = xpos = 0;
      ypos += 30;
    }
    newxpos += length;
    if (newxpos > maxwidth) maxwidth = newxpos;

    return 'translate(' + xpos + ',' + ypos + ')';
  });

var legendWidth = d3.select('.legendwrap').node().getBoundingClientRect().width;

legendWrap
  .attr("transform", function(d, i) {
    return "translate(" + (width - legendWidth) / 2 + "," + (height + 20) + ")";
  });
&#13;
&#13;
&#13;

提前感谢您的任何帮助或建议!

1 个答案:

答案 0 :(得分:0)

在谷歌搜索时,我遇到了同样的问题,即将图例项居中对齐。答案只有一半,我使用了您的代码并对其进行了修改,以实现中心对齐,如您的问题中所述。

基本上遍历图例项目两次,首先计算每行的x偏移量,然后在第二次中将其添加到该行中每个图例项目的x位置。

下面是两个循环,

    var ypos = 0, newxpos = 0, rowOffsets = [];
    var legendItemsCount = svg.selectAll('.legend').size();

    legend.attr("transform", function (d, index) {
        var length = d3.select(this).select("text").node().getComputedTextLength() + (legendRectSize + legendSpacing * 3);

        if (width < newxpos + length) {
            rowOffsets.push((width - newxpos) / 2);
            newxpos = 0;
            ypos += 30;
        }

        d.x = newxpos;
        d.y = ypos;
        d.rowNo = rowOffsets.length;
        newxpos += length;

        if (index === legendItemsCount - 1)
            rowOffsets.push((width - newxpos) / 2);
    });

    legend.attr("transform", function (d, i) {
        var x = d.x + rowOffsets[d.rowNo];
        return 'translate(' + x + ',' + d.y + ')';
    });