Посібник по D3.js: створюємо інтерактивні діаграми на JavaScript

12 хв. читання

Прочитавши статтю, ви дізнаєтесь як за допомогою D3.js запросто створити подібні діаграми:

chart

(Повний сирцевий код доступний за посиланням).

Що таке D3.js?

D3.js — data-driven JavaScript бібліотека для маніпулювання DOM елементами.

D3 дозволяє візуалізувати дані, використовуючи HTML, SVG та CSS. Акцент на веб стандарти дозволяє користуватися всіма можливостями сучасних браузерів без прив'язки до фреймворків, поєднуючи компоненти візуалізації та data-driven підхід до DOM маніпуляцій.

Навіщо створювати діаграми з D3.js? Чому б просто не користуватися зображеннями?

Діаграми базуються на інформації, яка надходить зі сторонніх ресурсів, а це вимагає динамічної візуалізації під час рендерингу.

Переваги SVG

SVG розшифровується як Масштабована Векторна Графіка (Scalable Vector Graphics), що технічно є мовою розмітки, яка базується на XML.

Найчастіше SVG використовується для створення векторної графіки, з виділенням ліній та форм або модифікації наявного зображення. Ви можете ознайомитись зі списком доступних елементів за посиланням.

Переваги:

  • Підтримується усіма передовими браузерами;
  • Має інтерфейс DOM, який не потребує сторонніх бібліотек;
  • Масштабований, може підтримувати високі розширення;
  • Менший розмір, якщо порівнювати з іншими форматами зображень.

Недоліки:

  • Може відображати лише двовимірні зображення;
  • Довготривалий процес вивчення;
  • Рендеринг проходить повільно через інтенсивні розрахункові операції.

Попри недоліки, SVG є гарним інструментом для зображення іконок, логотипів, ілюстрацій або, у даному випадку, діаграм.

Починаємо роботу з D3.js

Ми обрали саме гістограми, тому що вони є елементами з невисокою складністю відображення. У той же час, ми засвоїмо основи застосунку D3.js. Але зауважте: D3 надає великий набір інструментів для візуалізації даних. На github-сторінці проекту є дійсно круті приклади використання!

Діаграма може бути горизонтальною або вертикальною. Ми використовуватимемо вертикальну, яка ще називається гістограмою.

Для прикладу використаємо дані про 10 найулюбленіших мов програмування за версією Stack Overflow's 2018 Developer Survey result.

Розпочинаємо

SVG має свою координатну систему, яка має початок у верхньому лівому кутку (0;0). Вісь х з позитивними значеннями спрямована праворуч, у той час як вісь y — вниз. Таким чином, висота SVG враховується при обчисленні y — координати елемента.

coordinates

Створимо діаграму з шириною 1000px та висотою 600px.

<body>
<svg />
</body>
<script>
const margin = 60;
const width = 1000 - 2 * margin;
const height = 600 - 2 * margin;

const svg = d3.select('svg');
</script>

У фрагменті коду, наведеному вище, ми обираємо створений <svg> елемент у файлі HTML з select d3. Такий метод вибору приймає усі типи селекторних рядків і повертає перший відповідний елемент. Використовуйте selectAll, якщо хочете отримати усі елементи.

Я також визначаю значення margin, що додає трохи зайвого padding до діаграми. Padding може бути застосований з тегом <g>. З цієї миті ми використовуємо цю групу для збереження відстані від будь-якого іншого вмісту сторінки.

const chart = svg.append('g')
   .attr('transform', `translate(${margin}, ${margin})`);

Додати атрибути до елементу легко з викликом методу attr. Перший параметр методу приймає атрибут, який ми хочемо застосувати до обраного DOM елементу. Другий параметр — значення або колбек-функція, яка повертає це значення. Наведений код простим чином зміщує початок діаграми до позиції SVG (60;60).

Формати вводу, що підтримуються D3.js

Для початку, мені необхідно визначити джерело даних, необхідних для роботи. Використаємо одновимірний масив JavaScript, який утримує об'єкти з назвами мов програмування та їх процентним відношенням. Але варто зазначити, що D3.js підтримує різні формати даних.

Бібліотека має вбудований функціонал для завантаження даних з XMLHttpRequest, .csv файлів, текстових файлів та ін. Кожен з перелічених ресурсів має вміщувати дані, які D3.js може використовувати. Важливо наповнити ними масив. Зауважте: починаючи з версії 5.0 бібліотека використовує проміси для завантаження даних замість застарілих колбеків.

Масштабування, осі

Продовжимо з осями діаграми. Аби створити вісь y, необхідно встановити верхню та нижню межу, яка в нашому випадку становить 0 та 100 відповідно.

У статті використовуватимуться відсотки, але існують корисні функції для типів даних, відмінних від чисел, як будуть розглянуті пізніше.

Необхідно розподілити висоту діаграми на рівні частини між граничними значеннями. З цією метою створимо так звану функцію масштабування.

const yScale = d3.scaleLinear()
   .range([height, 0])
    .domain([0, 100]);

Лінійна шкала — найпопулярніший тип масштабування, що конвертує безперервну область вхідних значень у безперервний вихідний діапазон.

Зверніть увагу на методи range and domain. Перший приймає довжину, яка повинна розбиватися між межами області значень.

Пам'ятайте: система координат SVG починається у лівому верхньому кутку, тому діапазон приймає висоту як перший ненульовий параметр.

Створення осі зліва так само просто, як додати іншу групу та використати метод d3 axisLeft з функцією масштабування у ролі параметру.

chart.append('g')
   .call(d3.axisLeft(yScale));

Продовжимо з віссю x:

const xScale = d3.scaleBand()
   .range([0, width])
    .domain(sample.map((s) => s.language))
    .padding(0.2)
chart.append('g')
   .attr('transform', `translate(0, ${height})`)
    .call(d3.axisBottom(xScale));

axis

Зауважте, ми використовуємо scaleBand для осі x, що допомагає розбити діапазон на інтервали й підрахувати координати та ширину стовпців з додатковим значенням padding.

D3.js також може обробляти типи дат. scaleTime дуже схожий на scaleLinear, не враховуючи, що область значень у першому — масив дат.

Зображуємо стовпчики у D3.js

Поміркуємо над типом інпуту, який підійде для зображення стовпчиків, що представлятимуть прості фігури, зокрема прямокутники. У наступному фрагменті коду ми додаємо їх до створеного елемента групи:

chart.selectAll()
   .data(goals)
    .enter()
    .append('rect')
    .attr('x', (s) => xScale(s.language))
    .attr('y', (s) => yScale(s.value))
    .attr('height', (s) => height - yScale(s.value))
    .attr('width', xScale.bandwidth())

Спочатку ми викликаємо для елементів діаграми метод selectAll, який повертає пустий набір результатів. Потім функція data повідомляє скільки елементів DOM треба оновити, зважаючи на довжину масиву. enter ідентифікує елементи, що втрачаються, якщо введені дані переважають виділений обсяг. Повертається нова вибірка, яка представляє елементи, що треба додати. Зазвичай, далі застосовується append, який додає елементи в DOM.

У принципі, ми повідомляємо D3.js, що необхідно приєднати прямокутник до кожного члену масиву.

Таким чином, прямокутники додаються один на одного, при цьому не маючи довжину та ширину. Ці атрибути мають розраховуватись, тому функція масштабування знову стане у пригоді.

Погляньте, ми додаємо координати прямокутників з викликом attr. Другий параметр може бути колбеком, який приймає: фактичний елемент вхідних даних, його індекс та весь масив.

.attr('x', (actual, index, array) =>
   xScale(actual.value))

Функція масштабування повертає координату для даного значення з області. Підрахунок координат — це простіше простого. Увесь сенс у висоті стовпчика. Визначена координата у повинна бути вилучена зі значення висоти діаграми аби отримати правильне представлення кожного значення як стовпця.

Ми визначаємо ширину прямокутників так само з функцією масштабування. scaleBand містить функцію bandwidth, яка повертає визначену ширину для одного елемента, що базується на встановленому padding.

chart

Поради щодо створення гістограм

Існують деякі базові правила гістограм, які варто зазначити:

  • Уникайте використання 3D-ефектів;
  • Дотримуйтесь організації даних — за алфавітним порядком або сортуйте за певними ознаками;
  • Зберігайте відстань між стовпчиками;
  • Починайте вісь y з 0, а не з найменшого значення;
  • Використовуйте відповідні кольори;
  • Додавайте підписи до осей, заголовки, вказуйте джерела.

Система сіток у D3.js

Слід підкреслити значення, додавши сітку як фон.

Ви можете піти далі, експериментуючи з вертикальними та горизонтальними лініями. Але бажано використовувати щось одне. Надмірні лінії можуть відволікати. Наведений фрагмент коду показує як реалізувати обидва рішення:

chart.append('g')
   .attr('class', 'grid')
    .attr('transform', `translate(0, ${height})`)
    .call(d3.axisBottom()
       .scale(xScale)
        .tickSize(-height, 0, 0)
        .tickFormat(''))

chart.append('g')
   .attr('class', 'grid')
    .call(d3.axisLeft()
       .scale(yScale)
        .tickSize(-width, 0, 0)
        .tickFormat(''))

grid

Скористаємось горизонтальними лініями сітки, оскільки суцільна картина залишається простою та прийнятною для ока.

Підписи у D3.js

Також слід зробити діаграму більш детальною, додавши деякі текстові вказівники. Додамо назву до діаграми та осей.

labels

Усі написи є елементами, які можуть бути додані до SVG або груп. Вони можуть розміщуватись за координатами x та y, у той час як вирівнювання тексту здійснено з атрибутом text-anchor. Щоб додати напис, достатньо викликати метод text для текстового елементу.

svg.append('text')
   .attr('x', -(height / 2) - margin)
    .attr('y', margin / 2.4)
    .attr('transform', 'rotate(-90)')
    .attr('text-anchor', 'middle')
    .text('Love meter (%)')
svg.append('text')
   .attr('x', width / 2 + margin)
    .attr('y', 40)
    .attr('text-anchor', 'middle')
    .text('Most loved programming languages in 2018')

Інтерактивність з D3.js

Маємо досить інформативну діаграму, але є можливість додати трохи інтерактивності.

У наступному блоку коду ми розглянемо як додавати слухача події для SVG-елементів.

svgElement
   .on('mouseenter', function (actual, i) {
      d3.select(this).attr('opacity', 0.5)
    })
    .on('mouseleave', function (actual, i) {
       d3.select(this).attr('opacity', 1)
    })

Зазначте: тут використовуються функціональні вирази замість стрілкових функцій, для того, щоб отримати доступ до елементу з ключовим словом this.

Встановимо прозорість обраного SVG елементу як половину від початкового значення при наведенні курсору.

Ви також можете отримати координати курсору з d3.mouse. Повертається масив з координатами х та у. Таким чином, відображення підказки на кінці курсора не буде проблемою.

Створення інтерактивних діаграм — не так вже й просто

Існує декілька близьких значень, що відображаються на діаграмі, тому, щоб підкреслити різницю між значеннями стовпчиків, створимо слухача події для mouseenter. Кожного разу, коли користувач наводить курсор на певну колонку, горизонтальна лінія з'являється на верхівці стовпчика. Більш того, ми підраховуємо різницю, у порівнянні з іншими значеннями та відображаємо її на кожному стовпчику.

event-listener

Додамо прозорість та збільшив ширину даного стовпчика.

.on('mouseenter', function (s, i) {
   d3.select(this)
      .transition()
        .duration(300)
        .attr('opacity', 0.6)
        .attr('x', (a) => xScale(a.language) - 5)
        .attr('width', xScale.bandwidth() + 10)

    chart.append('line')
       .attr('x1', 0)
        .attr('y1', y)
        .attr('x2', width)
        .attr('y2', y)
        .attr('stroke', 'red')

    //це лише частина реалізації, огляньте сирцевий код
})

Метод transition вказує, що ми хочемо створити анімацію для змін у DOM. Інтервал вказано у функції duration, що приймає мілісекунди як аргументи. Наведені переходи затемнюють колір стовпчика та розширюють його.

Для створення SVG лінії мені необхідні точка відліку та призначення, які можна встановити координатами x1, y1 та x2, y2. Лінія не буде видимою до моменту встановлення її кольору з атрибутом stroke.

Це лише частина події mouseenter, тому майте на увазі: вам слід відновити або видалити зміни події mouseenter. Повний сирцевий код доступний у кінці статті.

Додамо трохи стилів до діаграми

Подивимось що ми вже реалізували до цього моменту, та як можемо оживити нашу діаграму з деякими стилями. Ви також можете додати атрибути класу до SVG елементів з функцією attr, яку ми вже використовували.

Діаграма має гарний набір функціоналу. Замість понурого, статичного зображення, відображається різниця між представленими даними при наведенні курсору. Заголовок вводить діаграму до контексту, а підписи допомагають ідентифікувати осі за одиницями виміру. Ми також додали підпис у правому нижньому кутку для позначення джерела статистичних даних.

Залишилось оновити кольори та шрифти!

Яскраві стовпчики добре виглядають на темному фоні.

Ви помітили, що лінія стала пунктирною? Таке можна досягнути шляхом встановлення stroke-width та stroke-dasharray атрибутів. З stroke-dasharray ви можете визначити візерунки, які змінюють контур форми.

line#limit {
   stroke: #FED966;
    stroke-width: 3;
    stroke-dasharray: 3 6;
}

.grid path {
   stroke-width: 3;
}

.grid .tick line {
   stroke: #9FAAAE;
    stroke-opacity: 0.2;
}

Лінії сітки тепер стають складними. Слід вказати stroke-width: 0 до траєкторії елементів, щоб приховати рамку діаграми, а також зменшити їх видимість шляхом встановлення прозорості ліній.

Інші правила CSS відповідають за розмір шрифтів та кольори, що можна побачити у сирцевому коді.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.6K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація