d3.js-计算先前绘制元素的宽度

d3.js-计算先前绘制元素的宽度,d3.js,svg,D3.js,Svg,我正在创建一个水平图例,显示在使用d3.js创建的条形图上方 这是我的第一次尝试,我努力想知道如何在图例中定位每个项目,以考虑到前一个项目的宽度 以下是我目前所看到的: 下面是我与图例渲染相关的代码: var legendRectSize = 18, legendSpacing = 4; svg.selectAll('.legend') .data(data.chartKeys) .enter() .append('g') .attr('class', 'legend') .attr

我正在创建一个水平图例,显示在使用d3.js创建的条形图上方

这是我的第一次尝试,我努力想知道如何在图例中定位每个项目,以考虑到前一个项目的宽度

以下是我目前所看到的:

下面是我与图例渲染相关的代码:

var legendRectSize = 18,
    legendSpacing = 4;

svg.selectAll('.legend')
.data(data.chartKeys)
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i) {
  //width = the chart area width
  var horz = width/2 + i*100; //This needs to add previously rendered elements width instead
  return 'translate(' + horz + ',' + 0 + ')';
});

svg.selectAll('.legend').append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.attr('class', function(d) {
  return d;
})
.style('stroke', 'black');

svg.selectAll('.legend').append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function(d) {
  return d;
});
正如您在transform函数中所看到的,我只是将每个项目的索引乘以100的因子,以使它们水平分布,但实际上我可以确定先前渲染元素的宽度(如此彩色的框和文本组合),并将其添加,以使它们之间的间距均匀,并且没有重叠

transform函数中是否有方法获取前一项,或者使用不同的方法是最好的


谢谢

如果您想要内联块样式布局,则需要根据实际文本宽度保留某种运行偏移量。您可以在此处看到一个示例:

其中的关键部分是将偏移量保持在外部范围内,然后使用
。每个
使用文本宽度更新偏移量:

var offset = 0;
var legendBlockWidth = 15;
var textMargin = 3;

legend.enter().append('g')
  .attr('class', 'legend')
  .each(function(key, i) {
    var item = d3.select(this);

    var text = item.append('text')
      .text(key);

    // ... snip ...

    // Translate the group based on the running width

    item.attr('transform', function() {
      return 'translate(' + offset + ',0)';
    });

    // Update the offset
    offset += text.node().getBBox().width + legendBlockWidth + textMargin * 3;
  });
您可以在此基础上使用一个变体来使用“最大文本宽度”,这将为您提供均匀的间距,而不会产生冲突:


如果需要内联块样式布局,则需要根据实际文本宽度保留某种运行偏移量。您可以在此处看到一个示例:

其中的关键部分是将偏移量保持在外部范围内,然后使用
。每个
使用文本宽度更新偏移量:

var offset = 0;
var legendBlockWidth = 15;
var textMargin = 3;

legend.enter().append('g')
  .attr('class', 'legend')
  .each(function(key, i) {
    var item = d3.select(this);

    var text = item.append('text')
      .text(key);

    // ... snip ...

    // Translate the group based on the running width

    item.attr('transform', function() {
      return 'translate(' + offset + ',0)';
    });

    // Update the offset
    offset += text.node().getBBox().width + legendBlockWidth + textMargin * 3;
  });
您可以在此基础上使用一个变体来使用“最大文本宽度”,这将为您提供均匀的间距,而不会产生冲突:


绘制DOM元素后,可以对其使用
.getBBox()
来获取其尺寸。然后,您可以根据该值重新调整位置。您可以在DOM元素上使用
.getBBox()
来获得绘制后的尺寸。然后你可以根据这一点重新调整位置。谢谢,这正是我想要的,问起来可能有点冒失,但如果项目超过可用宽度,有没有办法使其包裹起来,我在考虑响应性布局。使用SVG没有简单的方法可以做到这一点。如果您使用HTML作为图例,这是一个微不足道的问题;对于SVG,这是一个巨大的痛苦。感谢这正是我想要的,问起来可能有点无礼,但是如果项目超过可用宽度,是否有办法使其包裹,我在考虑响应性布局。对于SVG,没有简单的方法可以做到这一点。如果您使用HTML作为图例,这是一个微不足道的问题;对于SVG,这是一个巨大的痛苦。