Ранее мы получили наш первый рабочий пример d3. Это было не слишком сложно (надеюсь). Мы использовали select, selectAll, data, enter и т. д. Я немного говорил об аналогии с множествами, но не слишком подробно. Сегодня я хотел бы сделать шаг назад и немного поговорить об выборках (данные будут завтра).

Выбирать

Давайте начнем с чего-нибудь простого. Как выбрать первый элемент в приведенном ниже примере?

Чтобы выбрать первый элемент, мы могли бы использовать:

d3.select('#foo');

Это вернет нам массив с одним элементом в нем. Этот элемент будет ссылкой на наш элемент ‹div id="#foo"›.

Если вы посмотрите на ссылку, возвращаемую в массиве, вы увидите свойство с именем «parrentNode» (как на изображении ниже):

Сочтет это свойство полезным на более позднем этапе. А пока просто помните, что он существует.

Другой способ выбрать тот же элемент:

d3.select('div');

Это даст нам массив с одним элементом в нем. На этот раз он вернет нам только первый элемент, соответствующий нашему селектору. В этом случае первым элементом является наш элемент ‹div id=”#foo”›.

Выбрать все

SelectAll используется для одновременного выбора нескольких элементов.

Например:

d3.selectAll('div')

Это выберет все элементы div.

Обратите внимание, что этот выбор также имеет «родительский узел».

Как нам выбрать все элементы «svg»? Ну, мы могли бы сделать это:

d3.selectAll('svg')

Это даст нам массив с тремя элементами, которые являются нашими элементами svg.

Обратите внимание на «parrentNode» в выборе.

Теперь давайте попробуем выбрать все элементы «svg», которые являются дочерними элементами элемента «div»:

d3.selectAll('div svg');

Результат, который вы получите, должен быть таким же, как и раньше:

Чтобы выбрать все элементы «svg», которые являются дочерними элементами некоторого элемента div, мы могли бы сначала получить набор элементов «div», а затем оттуда выбрать наши элементы «svg»: как в:

d3.selectAll('div').select('svg');

Результат в этом примере эквивалентен примеру с одним селектором («div svg»).

Теперь давайте попробуем выбрать все элементы «div», а затем все элементы «svg» внутри элементов «div».

d3.selectAll('div').selectAll('svg')

Теперь мы получаем немного другой результат:

В результате получается массив массивов… Это круто. d3 сохранил иерархическую структуру элементов в DOM. Это очень полезное свойство d3, которое поможет вам с визуализацией.

Я призываю вас поиграть с выборами d3 и понять, как они работают. Это очень важно.

Работа с элементами

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

Начнем с изменения только первого элемента div (#foo). Чтобы отличить его от других элементов, мы сделаем его красным. Для этого нам нужно установить для свойства background-color значение «красный».

Для работы с атрибутами в d3 selection есть метод attr (https://github.com/d3/d3/wiki/Selections#attr).

Совет 1. Операторы контента применяют изменения ко всем элементам в выделенном фрагменте.

Совет 2. Операторы контента возвращают текущий выбор, поэтому вы можете связать несколько операторов вместе в кратком выражении.

Итак, чтобы сделать наш элемент #foo красным, мы делаем:

d3.select('#foo').attr('style', 'background-color: red');

Как насчет того, чтобы сделать все наши элементы div красными. Мы можем использовать selectAll вместо select. Нам также нужно выбирать по имени тега («div»), а не по идентификатору («#foo»).

d3.selectAll('div').attr('style', 'background-color: red');

Что ж, теперь, когда все наши элементы div стали красными, мы больше не можем их различать.

Если вы посмотрите документацию d3 для метода attr, вы увидите, что нам не нужно назначать статическое значение. Наше значение на самом деле может быть функцией. Если мы предоставим функцию вместо статического значения, для каждого элемента, для которого d3 устанавливает атрибут, сначала будет оцениваться функция, чтобы увидеть, каким должно быть это значение. Функция будет вызываться с двумя аргументами — датум и индекс (обычно сокращаются как ‘d’ и ‘i’ соответственно).

Итак, давайте назначим нашим элементам разные цвета. Мы сохраним цвета, которые хотим использовать, в массиве (для удобства) с именем colors:

var colors = ['red', 'green', 'blue'];

И теперь мы можем выбрать наши элементы и применить цвет фона на основе индекса в выборе:

d3.selectAll('div')
  .attr('style', function(d, i) { 
    return 'background-color: ' + colors[i];
  });

Теперь давайте сделаем что-то более сложное. Давайте добавим абзац в каждый div, и содержимое абзаца должно быть индексом элемента «div».

Давайте начнем со вставки элементов p в наши элементы div:

var inserted = d3.selectAll('div').append('p')

append вернет нам новый выбор (как показано на рисунке ниже):

Теперь мы можем использовать метод html для выбора, чтобы установить содержимое.

inserted.html(function(d, i) { return i; } );

Если вы посмотрите, какой метод html вернул, вы заметите, что он также вернул тот же выбор.

Эта функция d3 (возврат выбора) позволяет легко объединять методы/операции в цепочку. Два приведенных выше примера можно записать так:

d3.selectAll('div')
  .append('p')
  .html(function(d, i) { return i; } );

Вы увидите, что этот шаблон очень часто используется в d3.

Резюме

Мы видели, как d3 обрабатывает выборы. Мы использовали функции select, selectAll, attr и html, определенные при выборе. Вы будете использовать их очень часто, и я надеюсь, что вы хорошо их поняли. Если нет, я настоятельно рекомендую вам понять их, прежде чем перемещать один. d3 имеет действительно хорошую документацию, поэтому часто ссылайтесь на нее.