Javascript d3:根据前面元素的长度定位文本元素

Javascript d3:根据前面元素的长度定位文本元素,javascript,d3.js,Javascript,D3.js,我被困在d3(或者一般的JavaScript)中 我想用d3制作一个传奇。9个项目的位置应相互依赖。更具体地说: 这是我的简化阵列: var数据集=[“非洲”、“亚洲”、“加勒比”、“中美洲”、“欧洲”、“中东”、“北美”、“大洋洲”、“南美”] 在x轴上,我想进一步画下一个文本40px(向右),然后最后一个文本标签结束。我的意图是每次在圆圈之间都有相同的空间。因此,下一个文本始终取决于姓氏的长度 我试过这个: .attr("x", function(d, i) {return i * 40 +

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

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

这是我的简化阵列: var数据集=[“非洲”、“亚洲”、“加勒比”、“中美洲”、“欧洲”、“中东”、“北美”、“大洋洲”、“南美”]

在x轴上,我想进一步画下一个文本40px(向右),然后最后一个文本标签结束。我的意图是每次在圆圈之间都有相同的空间。因此,下一个文本始终取决于姓氏的长度

我试过这个:

.attr("x", function(d, i) {return i * 40 + d[i-1].length + 7;})
但是控制台说d[i-1]是未定义的

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

非常感谢!非常感谢你的帮助

埃瓦

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

以下是数组(硬编码x_位置为d[2]:var数据集=[ [“非洲”、“中美洲”、“中美洲”、“中美洲”、“中美洲”、“欧洲”、“欧洲”、“E9726C”、“255”、“中东”、“E3AC73”、“310”、“北美”、“B65856”、“383”、“大洋洲”、“287E5C”、“470”、“南美洲”、“5358”] ])


如何根据国家名称的长度绘制圆圈,并获得相同的圆圈间距?

首先,
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]引用更改为dataset[i-1]

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

您可以将返回声明更改为:

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

首先,
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]引用更改为dataset[i-1]

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

您可以将返回声明更改为:

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

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

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

完整示例:

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

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

完整示例:

我会这样做

//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]; 
        })
}
//这将是您的图例数组
var legendItems=[]
var legendCount=legendItems.length;
var legendSectionWidth=宽度/(legendCount+1);
//这将是你的“y”值。你可以分配你想要的任何东西。我已经使用了下面的如果是其他情况,你应该用你的逻辑替换它来计算y。
var-vert=0;
如果(legendPosition==“底部”){
如果(显示轴)
垂直=高度+legendVerticalPad+容器高度*0.04;
其他的
垂直=高度+legendVerticalPad+容器高度*0.02;
}
对于(变量i=0;i
结果是这样的

下面的图像证明,传说(文本和文本的组合)在所提供的宽度的中心上是从每个地方等距的,并且用这个逻辑,不管你需要什么样的传说,所有的东西都将被放置在彼此的距离上,并在屏幕的中间显示出来。


我希望这能有所帮助。

我会这样做的

//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]; 
        })
}
//这将是您的图例数组
var legendItems=[]
var legendCount=legendItems.length;
var legendSectionWidth=宽度/(legendCount+1);
//这将是你的“y”值。你可以分配你想要的任何东西。我已经使用了下面的如果是其他情况,你应该用你的逻辑替换它来计算y。
var-vert=0;
如果(legendPosition==“底部”){
如果(显示轴)
垂直=高度+legendVerticalPad+容器高度*0.04;
其他的
垂直=高度+legendVerticalPad+容器高度*0.02;
}
对于(变量i=0;i