D3.js перебирает массив объектов - PullRequest
2 голосов
/ 18 марта 2019

Я пытаюсь сделать ряд баров одинаковой высоты и ширины на основе заголовка.Имея массив из 100 объектов, каждый из них содержит ключ с именем , результаты , что само по себе и массив других 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 ]

2 голосов
/ 18 марта 2019

В вашем цикле вы добавляете элементы только первый раз в цикле: в массиве данных 20 элементов, прямоугольников в svg нет, поэтому вводятся все 20 элементов. Во второй раз в массиве данных 20 элементов, в svg 20 прямоугольников, поэтому выбор ввода пуст, новые данные просто связаны с 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, вы не используете idiomatic d3. Избегая цикла for для ввода элементов, масштабирование также становится проще, потому что мы не обновляем его постоянно, поскольку мы циклически перебираем родительский массив. Домен масштаба и диапазон должны быть установлены только один раз.

Вот обновленный codepen .

Теперь 2000 элементов приведут к очень маленьким прямоугольникам, возможно, шириной менее одного пикселя, и я не уверен, почему вы так масштабируете высоту столбцов, но это разные вопросы.

2 голосов
/ 18 марта 2019

Хорошее описание проблемы и CodePen - вам легко помочь!

Я сделал слегка измененную версию вашей Ссылка CodePen

По сути, произошлочто для каждой итерации в цикле for вы должны выбрать первые x (в вашем случае 20), соответствующие rect элементам.Это означает, что каждая итерация, после первой, будет просто заменять привязки данных к тем же элементам 20 rect на 20 записей данных текущей итерации.

Я сделал два изменения, чтобы исправить это:

  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 элементов, чтобы сделать это.

Дайте мне знать, если это поможет вам!

...