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