【问题标题】:d3.js - calculating width of a previously drawn elementd3.js - 计算先前绘制元素的宽度
【发布时间】:2015-12-03 03:07:19
【问题描述】:

我正在创建一个水平图例以显示在我使用 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;
});

正如您在转换函数中看到的那样,我只是将每个项目的索引乘以 100 以将它们水平展开,但实际上我可以确定先前渲染元素的宽度(所以彩色框和文本组合)并添加它,以便它们之间的间距是均匀的,并且没有任何重叠。

transform 函数中是否有一种方法可以获取前一个项目,或者其他方法是否最好?

谢谢

【问题讨论】:

  • 您可以在 DOM 元素上使用 .getBBox() 以在绘制它们后获取它们的尺寸。然后你可以根据它重新调整位置。

标签: d3.js svg


【解决方案1】:

如果您想要内联块样式布局,您需要根据实际文本宽度保留某种运行偏移量。你可以在这里看到一个例子:http://jsfiddle.net/nrabinowitz/r7yodrm1/

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

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;
  });

您可以对此使用变体来使用最大文本宽度,这样可以为您提供均匀的间距而不会发生冲突:http://jsfiddle.net/nrabinowitz/r7yodrm1/2/

var maxOffset = 0;

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

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

    // ... snip ...

    // Update the offset
    maxOffset = Math.max(
      maxOffset, 
      text.node().getBBox().width + legendBlockWidth + textMargin * 3
    );
  });

legend2.attr('transform', function(d, i) {
  return 'translate(' + (maxOffset * i) +',50)';
});

【讨论】:

  • 谢谢,这正是我所追求的,问起来可能有点厚颜无耻,但是如果项目超过可用宽度,有没有办法让它们换行,我正在考虑响应式布局。跨度>
  • 使用 SVG 没有简单的方法可以做到这一点。如果使用 HTML 作为图例,这是一个小问题;使用 SVG,这是一个巨大的痛苦。
猜你喜欢
  • 2014-03-26
  • 2016-08-16
  • 2018-01-02
  • 1970-01-01
  • 1970-01-01
  • 2013-07-27
  • 1970-01-01
  • 1970-01-01
  • 2022-06-14
相关资源
最近更新 更多