d3:位置文本元素取决于之前元素的长度

时间:2013-11-26 18:02:39

标签: javascript d3.js

我被困在d3(或一般的JavaScript)中。

我想用d3制作一个传奇。 9项的位置应相互依赖。更具体地说:

这是我的简化数组: var dataset = [" Africa"," Asia"," Caribbean"," Central America"," Europe", "中东","北美","大洋洲","南美"];

在x轴上,我想绘制下一个文本40px进一步(向右),然后最后一个文本标签结束。我的意图是每次都在圆圈之间留出相同的空间。因此,下一个文本始终取决于最后一个国家/地区名称的长度。

我试过了:

.attr("x", function(d, i) {return i * 40 + d[i-1].length + 7;})

但控制台说d [i-1]未定义。

我错过了什么?你会如何解决这个问题?

非常感谢提前!非常感激您的帮忙!

埃娃

更新: 实际上我想要绘制的图例不仅包括文字,还包括小圆圈。

这是数组(硬编码的x_pos为d [2]:var dataset = [            ["非洲","#4B7985",5],["亚洲","#58AB86",55],[&#34 ;加勒比","#63A4B5",100],["中美洲","#818181",165],["欧洲&# 34;,"#E9726C",255],["中东","#E3AC73",310],["北美" ,"#B65856",383],["大洋洲","#287E5C",470],["南美",&# 34;#AC8358",530]             ];

如何根据国家/地区名称的长度绘制圆圈并在cirlces之间获得相同的间距?

3 个答案:

答案 0 :(得分:4)

您可以绘制文本元素以在画布上获取边界框。然后根据最后一个元素的宽度调整位置:

svg.selectAll("text")
  .data(data).enter()
  .append("text")
  .attr("x", function(d) {
    return x_pos;
  })
  .attr("y", 50)
  .style("display", "none")
  .text(function(d) { return d; });

svg.selectAll("text")
  .style("display", "block")
  .attr("x", function(d) {
    var c_pos = x_pos;
    x_pos = x_pos + this.getBBox().width + distance;
    return c_pos;
  });

完整示例:https://vida.io/documents/C5CSjbWLhoJ8rQmhF

答案 1 :(得分:1)

我就是这样做的。

//This will be your array of legends
var legendItems = [] 

var legendCount = legendItems.length;
var legendSectionWidth = width / (legendCount+1);
//This will be your "y" value going forward. You can assign anything you want. I have used the following if else case, you should replace it with your logic to calculate y.
var vert = 0;
if(legendPosition == "bottom"){
    if(showAxes)
        vert = height + legendVerticalPad + containerHeight*0.04;
    else
        vert = height + legendVerticalPad + containerHeight*0.02;
}

for(var i = 0; i < legendCount; i++){
    var text = svg.append('text')
        .attr('x', (i+1)*legendSectionWidth)
        .attr('y', vert)
        .attr('class', 'legend-text '+legendItems[i])
        .style('text-anchor', 'middle')
        .style('dominant-baseline', 'central')
        .text(function() {
            return legendItems[i];
        });

    var len = text[0][0].getComputedTextLength();

// you could use circles here, just change the width n height to rx and x and y to cx and cy// you could use circles here, just change the width n height to rx and x and y to cx and cy`enter code here`
//The value 5 is your choice, i use 5px between my rect and text
    svg.append('rect') 
        .attr('x', (i+1)*legendSectionWidth - len/2 - 5 - legendRectSize)
        .attr('y', vert - legendRectSize/2)
        .attr('width', legendRectSize)
        .attr('height', legendRectSize)
        .attr('class', function () { return 'legend '+ legendItems[i];} )
        .attr('label', function()  {
            return legendItems[i]; 
        })
}

结果是这样的 Sample legends

以下图像证明了图例(矩形和文本的组合)与每个图例等距,并且位于所提供宽度的中心。有了这个逻辑,无论你需要什么样的传说,所有的都将被放置在彼此相等的位置并显示在屏幕中间

5 legends

4 legends

3 legends

2 legends

1 legend

我希望这会有所帮助。

答案 2 :(得分:0)

首先,d指的是单个绑定数据点,而i指的是数据集中的索引。要查看以前的数据点,您需要引用原始数据集,而不是提供的数据点。

假设你有:

var dataset = ["Africa","Asia", "Caribbean", "Central America", "Europe", "Middle East", "North America", "Oceania", "South America"];

d3.select('.foo').data(dataset)....

您可能希望将位置处理程序中的d [i - 1]引用更改为数据集[i - 1]

修复后,你的第一个元素仍会爆炸,因为它位于dataset[0]。在这种情况下,dataset[i - 1]dataset[-1]

您可以将return语句更改为:

return i ? (i * 40 + dataset[i-1].length + 7) : i;