[英]D3.js looping through an array of objects
我正在尝试根据标题制作一排高度和宽度相等的条形图。 有一个100个对象的数组,每个对象包含一个称为result的键 ,它本身和其他20个对象的数组,因此最终结果必须是一行2000条,但是我只能得到20条:
Codepen: https ://codepen.io/ekilja01/pen/RdJqGO
数据是一个对象数组,具有一个称为result的对象数组,格式如下:
0:
page: 1
results: Array(20)
0: {vote_count: 17968, id: 19995, video: false, vote_average: 7.4, title: "Avatar", …}
...
length: 20
1: {page: 2, total_results: 406130, total_pages: 20307, results: Array(20)}
2: {page: 3, total_results: 406130, total_pages: 20307, results: Array(20)}
这是我的方法:
d3.json('data.json').then(data => {
console.log(data);
for (let i = 0; i < data.length; i++) {
//x and y domain
xScale.domain(data[i].results.map(d => d.title));
yScale.domain(data[i].results.map(d => d.original_title));
svg.selectAll('rect')
.data(data[i].results)
.enter()
.append('rect')
.style('fill', 'red')
.attr('width', xScale.bandwidth())
.attr('height', 70)
.attr('x', function (d) {
return xScale(d.title);
})
.attr('y', function (d) {
return yScale.bandwidth() + 175;
});
}
}).catch(error => console.log(error));
精美的问题描述和CodePen-轻松帮助您!
我已经为您的CodePen链接做了一个稍微修改的版本
基本上,发生的事情是,对于for循环中的每个迭代,您都将选择前x个(在您的情况下为20个)匹配的rect
元素。 这意味着在第一次迭代之后,每次迭代都将使用当前迭代的20个数据条目替换与相同的20个rect
元素的数据绑定。
我进行了两种更改来解决此问题:
svg.selectAll('rect')
更改为svg.selectAll('.rect_${i}')
,这将选择具有相应类( .rect_0
, .rect_1
等)的所有元素。 这样做可以防止覆盖先前的rect
元素。 .attr('x')
的回调函数中添加+ xScale.range()[1] * i
。 这会将每20个rect
元素向右移动,以确保rect
元素不会相互绘制。 但是,要点2确实可以绘制出非常宽的图表。 如果您希望各行之间彼此相邻,我使用rect
元素的高度添加了功能(在注释中)。
让我知道这是否对您有帮助!
在循环中,仅在循环中第一次添加元素:数据数组中有20个项目,svg中没有矩形,因此输入了全部20个项目。 第二次在数据数组中有20个项目,在svg中有20个矩形,因此enter选择为空,新数据仅绑定到20个现有矩形。
作为其他答案的替代方法,您的数据似乎不是分层的,但是您具有分层的结构。 如果您的数据结构与DOM结构相同,那么这将更加简单。 让我们对数据进行一些重组:
var combined = [];
for (let i = 0; i < data.length; i++) {
combined.push(...data[i].results);
}
现在我们的数据是:
[
{vote_count: 17968, id: 19995, video: false, vote_average: 7.4, title: "Avatar", …,}
{...},
{...},
...
并且所有要映射的对象都在一个数组中,该数组中的一项,一个要添加到图表中的元素。 现在我们可以做一个简单的输入循环:
svg.selectAll('rect')
.data(combined)
.enter()
.append('rect')
.style('fill', 'red')
.attr('width', xScale.bandwidth())
.attr('height', 70)
.attr('x', function (d) {
return xScale(d.title);
})
.attr('y', function (d) {
return yScale.bandwidth() + 175;
});
通常,如果需要循环以在DOM中输入元素,则无需使用惯用的d3。 通过避免for循环输入元素,缩放也变得更加容易,因为在遍历父数组时我们不会不断更新它。 比例域和范围只需设置一次。
这是更新的codepen 。
现在,2000个元素将生成非常小的矩形,可能小于一个像素宽,我不确定为什么要像这样缩放条形的高度,但这是不同的问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.