Введение в d3.js

Что такое d3.js?

Зрение обеспечивает нас более 90% от общего объема информации, которую получаем, именно поэтому самый эффективный способ сделать анализ большого объёма данных — представить их визуально. Пытаясь на практике найти оптимальный способ представления информации, я наткнулся на библиотеку d3.js и понял, что именно на её основе можно в полной мере воплотить мои идеи.

Название d3 расшифровывается как data driven document. Это JavaScript библиотека, ориентированная на работу с данными и их визуальное представление для веба, включая загрузку данных, визуализацию в режиме реального времени и множество других возможностей. Здесь можно найти много вдохновляющих примеров практического применения d3.js.

В чём сложность?

Множество библиотек, основанных на d3.js, предоставляет пользователю готовый набор функциональных возможностей, без необходимости вникать во все технические тонкости визуализации. Эти библиотеки ограничиваются стандартными графиками и диаграммами, в то время как возможности d3.js ограничены только вашим воображением и техническими возможностями платформы, что даёт возможность сосредоточиться на самих данных и создавать визуализации любой сложности.

В основе d3.js лежат такие веб-стандарты:

При изучении d3.js желательно в должной мере владеть этими технологиями. Это основная проблема при изучении d3.js — порог входа, как показывает практика, довольно высок.

Изучение d3.js позволит углубить и систематизировать знания и представления о веб-стандартах.

С чего начать?

Один из самых важных для понимания работы d3.js аспектов — присоединение данных к элементам (data join).

Рассмотрим все аспекты присоединения данных на примере:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <script type="application/javascript" src="http://d3js.org/d3.v3.min.js"></script>
  </head>
  <body>
    <script type="application/javascript">
      d3.select('body').selectAll('p')
        .data([16, 23, 42])
        .enter()
        .append('p')
        .text("Hello");
    </script>
  </body>
</html>

Рассмотрим пошагово интересующий нас фрагмент кода:

d3.select('body').selectAll('p')
  .data([16, 23, 42])
  .enter()
  .append('p')
  .text("Hello");

В d3.js мы пишем, вызывая всё последовательно цепочкой методов (так называемый chain syntax).

Схема

Схема

Схема

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

А где, собственно, сами данные?

Как я указал ранее, данные хранятся в атрибуте "__data__" элемента. Обратиться к нему можно через анонимную функцию. Например, вместо текста “Hello” можно вставить наши данные:

.text(function(d) { return d; })

Схема

Анонимная функция вторым параметром может принимать текущий индекс элемента, а так же внутри себя имеет объект this, который ссылается на текущий элемент (в данном случае — <p>).

.text(function(d, i) {
    console.log(this);
    console.log(i, "-", d);
    return (d + 2 * i);
})

Различные варианты привязки данных

Есть 2 способа привязки: по индексу и по ключу.

Рассмотрим привязку данных по индексу

Для этого сделаем новую привязку с другими данными. Новую привязку мы выделим в отдельную переменную:

var p = d3.select('body').selectAll('p')
    .data([45, 16, 87, 108]);

Теперь в переменной p к каждому существующему элементу по его индексу было переприсвоено новое значение (первое значение записано в массив под индексом 0, второй под индексом 1 и т.д.) и зарезервировано место для нового элемента.

Схема

Так же в переменной p хранятся три состояния выборки (enter, update, exit). В выборку enter() ушёл один элемент. Добавим его.

p.enter().append('p');

Схема

Теперь у нас есть новые данные для каждого параграфа. Осталось используя их обновить содержимое параграфов:

.text(function(d) { return d; });

Старые данные ушли в выборку exit() и их можно удалить:

p.exit().remove();

Теперь рассмотрим привязку данных по ключу

Когда вторым аргументом data() является анонимная функция, то привязка происходит по ключу:

var p = d3.select('body').selectAll('p')
        .data([45, 16, 87, 108], function(d) { return d; });

В данном случае мы возвращаем само значение. Важно понимать, что совпадающие по значению объекты игнорируются, например, если в данных уже есть объект 16, то в новых данных при добавлении он не будет учитываться.

Схема

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

var data1 = [
    {"name": "Ringo", "height": 175},
    {"name": "Paul", "height": 190}
];

var data2 = [
    {"name": "Paul", "height": 190},
    {"name": "Sam", "height": 170}
];

d3.select('body').selectAll('p')
  .data(data1)
  .enter()
  .append('p')
  .text(function(d) { return d.height; });

var p = d3.select('body').selectAll('p')
          .data(data2, function(d) { return d.name; });
p.enter().append('p');
p.exit().remove();
p.text(function(d) { return d.height; });

Привязка происходит по уникальному ключу (в данном случае по ключу "name").

var p = d3.select('body').selectAll('p')
          .data(data2, function(d) { return d.name; });

Схема

Сейчас у нас в exit выборке один элемент на удаление и в enter выборке один элемент на добавление.

Ещё раз про три состояния enter, update, exit

data() предоставляет три выборки для реализации отношений между элементами и данными. Выбор состояния зависит от кол-ва данных и элементов.

Если данных больше чем элементов, то новые элементы попадают в enter() выборку для добавления.

В случае, если у нас на руках данных меньше, чем есть сейчас элементов, лишние элементы попадают в exit() выборку и удаляются.

Если кол-во данных совпадает с кол-вом элементов, то происходит обновление, данных с последующим удалением старых данных, находившихся в элементах.

Заключение

Вопросы, затронутые в статье, может показаться довольно сложными для понимания. Дополнительную информацию можно прочесть здесь и посмотреть тут. Как всегда, практика — ключ к успеху. Пробуйте всё изложенное своими руками. Будут возникать вопросы — пишите в комментариях.