D3.js遍历对象数组

时间:2019-03-18 13:52:34

标签: javascript arrays json object d3.js

我正在尝试根据标题制作一排高度和宽度相等的条形图。数组包含100个对象,每个对象都包含一个称为 results key ,它本身以及其他20个对象的数组,因此最终结果必须是一排2000条,但是我只得到20条:

wrong output

Codepen:https://codepen.io/ekilja01/pen/RdJqGO

数据是一个对象数组,具有名为 结果 的对象数组,格式如下:

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

2 个答案:

答案 0 :(得分:2)

好的问题描述和CodePen-可以轻松帮助您!

我为您的CodePen link作了一个简短修改的版本

基本上,发生的事情是对于for循环中的每个迭代,您将选择匹配rect元素的前x个(在您的情况下为20个)。这意味着,在第一次迭代之后,每次迭代都将用当前迭代的20个数据条目替换与相同的20个rect元素的数据绑定。

我进行了两项更改以解决此问题:

  1. svg.selectAll('rect')更改为svg.selectAll('.rect_${i}'),以选择具有相应类(.rect_0.rect_1等)的所有元素。这样做可以防止覆盖先前的rect元素。
  2. + xScale.range()[1] * i添加到.attr('x')的回调函数中。这样会将每20个rect元素移到右侧,以确保rect元素不会相互重叠。

第2点的确可以绘制出非常宽的图表。如果您希望各行之间彼此相邻,我使用了rect元素的高度添加了功能(在注释中)。

让我知道这是否对您有帮助!

答案 1 :(得分:2)

在循环中,您仅在循环中第一次添加元素:数据数组中有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个元素将生成非常小的矩形,可能小于一个像素宽,我不确定为什么要像这样缩放条形的高度,但这是不同的问题。 / em>