2015-12-02 120 views
0

我创建了一个水平图例,显示在我用d3.js创建的条形图上方。d3.js - 计算以前绘制的元素的宽度

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

所以这是我看到目前为止:

enter image description here

这里是我的代码相关的传说渲染:

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来横向扩展它们,但实际上我可以通过确定先前渲染的元素的宽度(如此彩色的框和文本组合)并添加它来代替spacin他们之间的平衡是平等的,没有任何重叠。

在转换函数中是否有一种方法可以获得前一个项目或最佳方法?

感谢

+0

你可以用'.getBBox()'的DOM元素来获得它们的尺寸,一旦他们被吸引。然后你可以根据这个重新调整位置。 –

回答

3

如果你想要一个inline-block的风格布局,你需要保持某种基于真实文本宽度运行偏移。你可以在这里看到一个例子: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)'; 
}); 
+0

谢谢,这正是我之后,它可能有点厚颜无耻的问,但有没有办法使项目包装,如果他们超过了可用宽度,我正在考虑为响应式布局。 – mindparse

+0

有没有简单的方法与SVG做到这一点。如果您使用HTML作为图例,这是一个微不足道的问题;用SVG,这是一个巨大的痛苦。 – nrabinowitz