Cubecubed 💖 d3.js

d3.js — это библиотека JavaScript, используемая для манипулирования DOM с помощью простого синтаксиса. Вы можете рассматривать ее как версию jQuery нового поколения, но не совсем. d3.js фокусируется на визуализации данных. Кроме того, он помогает работать с анимацией, воспроизводимой способом tweening (а не WebAPI’s requestAnimationFrame).

Cubecubed интенсивно использует d3 во всех классах кубиконов, связанных с SVG. В этой статье я покажу вам основные вещи, которые необходимо знать о d3, и в конце объясню, как Cubecubed использует его для абстрагирования процесса рендеринга SVG в классах.

Итак, давайте начнем с основных методов d3.

append(), select(), attr() и style().

В index.html мы определяем эти теги внутри элемента <body>:

<h1>Hello</h1>
<h1>World</h1>
Вход в полноэкранный режим Выйти из полноэкранного режима

Есть и другой способ добиться этого полностью на JavaScript. В этом случае нам не нужно редактировать HTML-файл.

d3.select("body")
  .append("h1")
  .text("Hello");

d3.select("body")
  .append("h1")
  .text("World");
Вход в полноэкранный режим Выход из полноэкранного режима

Когда мы вызываем метод select("body"), d3 найдет первый элемент body и вернет его объект d3 selection.

Далее мы выделяем первый <h1> следующим образом:

d3.select('h1');
Войти в полноэкранный режим Выйти из полноэкранного режима

Затем, если мы применим атрибут к элементу, мы можем просто соединить код выше с методом attr().

d3.select('h1')
  .attr('class', 'hello');
Войти в полноэкранный режим Выход из полноэкранного режима

Отрисованный HTML в браузере будет выглядеть следующим образом:

<h1 class="hello">Hello</h1>
<h1>World</h1>
Вход в полноэкранный режим Выход из полноэкранного режима

Как мы можем применить стили CSS к элементу? Вы догадались.

d3.select('h1')
  .attr('class', 'hello')
  .style('color', 'red');
Войти в полноэкранный режим Выйти из полноэкранного режима

Магия объединения данных

Рассмотрим эту структуру HTML:

<h1>red</h1>
<h1>green</h1>
<h1>blue</h1>
Вход в полноэкранный режим Выход из полноэкранного режима

Как мы можем добавить соответствующий цвет к каждому из элементов h1? Один из способов сделать это — добавить классы, select() элементы и применить цвета к каждому из них. Что-то вроде этого будет работать:

<h1 class="red">red</h1>
<h1 class="green">green</h1>
<h1 class="blue">blue</h1>
Войти в полноэкранный режим Выйти из полноэкранного режима
d3.select(".red")
  .style("color", "red");

d3.select(".green")
  .style("color", "green");

d3.select(".blue")
  .style("color", "blue");
Войти в полноэкранный режим Выйти из полноэкранного режима

Каковы недостатки этого подхода? Мы должны добавить пользовательские классы для трех элементов h1, а затем нарушить принцип DRY, переписав классы при применении цветов. Представьте себе большую проблему, где у нас сотни элементов, не знаю, как вы, но я не буду утруждать себя добавлением сотен классов, а затем писать сотни методов select().

Возможно, ваш подход отличается от моего, но в d3 встроен потрясающий метод, который отлично работает в этой ситуации. Это метод data().

Сначала определим массив цветовых строк.

const colors = ["red", "green", "blue"];
Вход в полноэкранный режим Выход из полноэкранного режима

После этого мы бибидим-бибидим-бибидим-бибибидим с помощью этих строк кода.

d3.selectAll("h1")
  .data(colors)
  .style((d, i) => d);
Войти в полноэкранный режим Выход из полноэкранного режима

И бум, все просто работает!

Что здесь происходит? Во-первых, мы выделяем все элементы h1, затем вызываем для них метод data(). С этого момента каждый следующий метод в текущей цепочке может принимать анонимную функцию с d и i в качестве параметров. Эти два параметра точно такие же, как в методе JavaScript map(): d — это текущий элемент, а i — его индекс в массиве.

Всего три строки кода, и нам не нужно добавлять классы или вызывать метод сотни раз. Разумный результат заключается в том, что массив (вместе с объектами — это data в d3) нужно обновлять до ста раз, что не является большой проблемой, если у вас активно работает хранилище данных.

Такова природа термина «визуализация данных» в d3. При передаче все большего количества данных в метод data() мы можем даже создать множество элементов SVG, чтобы легко визуализировать данные с помощью графиков или диаграмм.

transition() kickstart

Следующая вещь, которая делает d3 зверем, — это его метод transition(). Я использовал его во всех типах SVG-анимации в Cubecubed.

Больше никаких разговоров, давайте погрузимся в код прямо сейчас.

Сначала мы добавляем в тело SVG элемент <circle>. Возвращенное выделение должно быть присвоено переменной.

const circleSelection = d3.select("body")
  .append("circle")
  .attr("cx", 50)
  .attr("cy", 50)
  .attr("r", 50)
  .attr("fill", "none")
  .attr("stroke", "#ffc777");
Вход в полноэкранный режим Выход из полноэкранного режима

Чтобы перевести отрисованный круг, мы вызываем transition() для переменной selection.

circleSelection
  .transition()
  .delay(1000)
  .duration(2000)
  .attr("transform", "translate(50, 50)");
Вход в полноэкранный режим Выход из полноэкранного режима

В приведенном выше коде мы задаем время задержки (количество времени до того, как анимация будет воспроизведена — в миллисекундах, поэтому 1000ms = 1s), а также продолжительность анимации. В частности, анимация ждет 1 секунду, затем медленно изменяет атрибуты SVG transform, пока не достигнет значения translate(50, 50). Для завершения работы твина требуется 2 секунды.

Причина, по которой мы привязываем атрибут translate, а не cx и cy, заключается в том, что он появляется во всех элементах SVG, тогда как два последних определены специально для <circle>. В Cubecubed типы кубиконов имеют различные базовые элементы, от <circle> до <line> и так далее. К этому моменту я хочу использовать класс анимации Translate для всех них.

Принцип Cubecubed для создания новых типов кубиконов

Все типы кубиконов должны быть производными от абстрактного класса Cubicon. Есть два обязательных свойства: g_cubiconWrapper и def_cubiconBase, которым в конструкторе нужно присвоить выделения d3. Первый является элементом SVG <g>, который оборачивается вокруг второго, который является любым элементом SVG, который непосредственно отображается на экране.

Весь метод append() должен быть помещен внутрь конструктора. Если поместить его в метод render(), структура HTML будет заполняться добавляемыми элементами каждый раз, когда пользователи будут вызывать этот метод, что приведет к беспорядку.

Заключение

Это все, что вам нужно знать о библиотеке d3 и о том, как Cubecubed отображает свои кубы.

Оцените статью
devanswers.ru
Добавить комментарий