Визуализация данных при помощи DataTables.js и Highcharts.js
Russian (Pусский) translation by AlexBioJS (you can also view the original English article)
Из данного руководства вы узнаете, как визуализировать данные, воспользовавшись библиотеками JavaScript DataTables.js и Highcharts.js.
Вот, что мы будем создавать (гляньте более крупную версию для лучшего восприятия):
Необходимые библиотеки
Для целей этого примера нам необходимо будет загрузить следующие библиотеки в наш пэн (* проект. Здесь и далее примеч. пер.):
- jQuery
- DataTables.js
- Highcharts.js
Помня об этом, при переходе на вкладку Settings (* Настройки) вы увидите, что я подключил один внешний файл CSS (* Cascading Style Sheets - каскадные таблицы стилей):



Подобным образом я также подключил четыре внешних файла JavaScript:



Примечание: нам необходимо добавить библиотеку jQuery в наш проект, поскольку DataTables.js является плагином jQuery. Однако, помните, что Highcharts.js является библиотекой на чистом JavaScript, и поэтому используется без jQuery.
Код HTML
Для начала мы определяем элемент класса container, который содержит два подэлемента:
- Таблицу с 26 строками. Первая строка относится к заголовкам таблицы
th, а остальные 25 строк содержат подробности о странах. Источником данных нашего примера является worldometers.info. - Пустой элемент
div, в котором будет располагаться диаграмма.
Ниже располагается структура кода HTML:
1 |
<div class="container"> |
2 |
<table id="dt-table"> |
3 |
<thead>
|
4 |
<tr>
|
5 |
<th>Country</th> |
6 |
<th>Population (2017)</th> |
7 |
<th>Density (P/Km²)</th> |
8 |
<th>Med. Age</th> |
9 |
</tr>
|
10 |
</thead>
|
11 |
<tbody>
|
12 |
<tr>
|
13 |
<td>China</td> |
14 |
<td>1,409,517,397</td> |
15 |
<td>150</td> |
16 |
<td>37</td> |
17 |
</tr>
|
18 |
|
19 |
<!-- 24 more rows here -->
|
20 |
|
21 |
</tbody
|
22 |
</table> |
23 |
|
24 |
<div id="chart"></div> |
25 |
</div>
|
Стоит отметить, что ради наглядности мы прописали данные прямо в вышеупомянутой таблице. Тем не менее, в реальных проектах таблицы должны создаваться динамически.
После создания разметки документа HTML и добавления цвета фона для разборчивости проект выглядит следующим образом:
Код CSS
На данном этапе мы определяем некоторые основные стили следующим образом:
1 |
.container { |
2 |
display: flex; |
3 |
flex-wrap: wrap; |
4 |
align-items: center; |
5 |
padding: 0 10px; |
6 |
}
|
7 |
|
8 |
#dt-table_wrapper { |
9 |
width: 35%; |
10 |
margin-right: 2%; |
11 |
}
|
12 |
|
13 |
#chart { |
14 |
width: 63%; |
15 |
}
|
16 |
|
17 |
table { |
18 |
text-align: left; |
19 |
}
|
20 |
|
21 |
@media screen and (max-width: 1200px) { |
22 |
#dt-table_wrapper, |
23 |
#chart { |
24 |
width: 100%; |
25 |
}
|
26 |
|
27 |
#dt-table_wrapper { |
28 |
margin-right: 0; |
29 |
}
|
30 |
}
|
Необходимо, чтобы вы понимали, что:
- В нашей разметке идентификатор
#dt-table_wrapperотсутствует. Он добавляется плагином DataTables, как только мы его инициализируем. - Несмотря на то, что мы определяем несколько правил для маленьких экранов, обратите внимание, что демоверсия не будет соответствовать всем требованиям отзывчивого веб-дизайна. Есть множество дополнений, которые мы можем внести для улучшения вида таблицы и диаграммы на устройствах с маленьким экраном. Например, для DataTables имеется расширение Responsive. Но это выходит за рамки обсуждаемой в этом руководстве темы.
После создания CSS давайте посмотрим, как выглядит проект. Пока что мы не заметим большой разницы, поскольку мы не инициализировали библиотеку:
Код JavaScript
Теперь переходим к окну JavaScript нашего пэна. После построения DOM (* Document Object Model - объектная модель документа) - дерева выполняется функция init. Эта функция запускает другие подфункции:
1 |
function init() { |
2 |
const table = $("#dt-table").DataTable(); |
3 |
const tableData = getTableData(table); |
4 |
createHighcharts(tableData); |
5 |
setTableEvents(table); |
6 |
}
|
Как вы увидите, каждая из этих подфункций выполняет определенное задание.
Инициализация таблицы вида ’DataTables’
Сначала нам необходимо преобразовать нашу таблицу в таблицу вида ’DataTables’. Мы можем это осуществить всего лишь при помощи одной строки кода: $("#dt-table").DataTable();
Если мы теперь посмотрим на таблицу, то заметим, что она приобрела возможности таблицы вида ’DataTables’, то есть: мы можем проводить в ней сортировку данных, осуществлять поиск по ней и т.д. Поэкпериментируйте с ней в следующей демоверсии:
Как вы видите, теперь с использованием DataTables к таблице применяется сортировка по умолчанию. При необходимости мы можем изменить ее параметры.
Извлечение данных таблицы
Следующий шаг - это извлечение данных таблицы и построение графика. Нам не нужны все данные таблицы. Действительно, если вы посмотрите на окончательную версию нашей демонстрационной программы, то заметите, что на графике приведены только данные первых трех столбцов (* Country - Страна, Population - Численность населения, Density - Плотность населения).



Помня об этом, для того чтобы получить необходимые данные, мы воспользуемся API (* Application Programming Interface - программный интерфейс приложения) DataTables. Для реализации вышесказанного имеется следующая функция:
1 |
function getTableData(table) { |
2 |
const dataArray = [], |
3 |
countryArray = [], |
4 |
populationArray = [], |
5 |
densityArray = []; |
6 |
|
7 |
// loop table rows
|
8 |
table.rows({ search: "applied" }).every(function() { |
9 |
const data = this.data(); |
10 |
countryArray.push(data[0]); |
11 |
populationArray.push(parseInt(data[1].replace(/\,/g, ""))); |
12 |
densityArray.push(parseInt(data[2].replace(/\,/g, ""))); |
13 |
});
|
14 |
|
15 |
// store all data in dataArray
|
16 |
dataArray.push(countryArray, populationArray, densityArray); |
17 |
|
18 |
return dataArray; |
19 |
}
|
Внутри этой функции мы пробегаемся по строкам таблицы, извлекаем из каждой строки данные необходимого столбца и сохраняем их в соответствующих массивах. В конце все эти массивы сохраняются внутри другого массива.
Ниже приведена краткая визуализация основного (то есть dataArray) массива:



Перед тем, как идти далее, необходимо понять одну вещь. По умолчанию функция getTableData должна извлекать данные из всех строк таблицы. Но если мы осуществляем поиск чего-то определенного в таблице, то только строки, удовлетворяющие критериям поиска, должны извлекаться и обрабатываться. Для осуществления этого мы передаем в функцию rows параметр. Это объект, свойству search которого присвоено значение "applied".
Опять-таки заметьте, что если мы не передадим этот объект, то всегда будем извлекать данные из всех строк таблицы (проверьте это). Для получения дополнительной информации о свойствах, которые мы можем указать у этого объекта, перейдите на эту страницу.
Построение графика
Теперь, когда у нас имеются необходимые данные, мы готовы к построению графика. Он будет включать два вложенных графика: столбчатую диаграмму и сплайновую кривую.
Ниже приводится соответствующая функция:
1 |
function createHighcharts(data) { |
2 |
Highcharts.setOptions({ |
3 |
lang: { |
4 |
thousandsSep: "," |
5 |
}
|
6 |
});
|
7 |
|
8 |
Highcharts.chart("chart", { |
9 |
title: { |
10 |
text: "DataTables to Highcharts" |
11 |
},
|
12 |
subtitle: { |
13 |
text: "Data from worldometers.info" |
14 |
},
|
15 |
xAxis: [ |
16 |
{
|
17 |
categories: data[0], |
18 |
labels: { |
19 |
rotation: -45 |
20 |
}
|
21 |
}
|
22 |
],
|
23 |
yAxis: [ |
24 |
{
|
25 |
// first yaxis
|
26 |
title: { |
27 |
text: "Population (2017)" |
28 |
}
|
29 |
},
|
30 |
{
|
31 |
// secondary yaxis
|
32 |
title: { |
33 |
text: "Density (P/Km²)" |
34 |
},
|
35 |
min: 0, |
36 |
opposite: true |
37 |
}
|
38 |
],
|
39 |
series: [ |
40 |
{
|
41 |
name: "Population (2017)", |
42 |
color: "#0071A7", |
43 |
type: "column", |
44 |
data: data[1], |
45 |
tooltip: { |
46 |
valueSuffix: " M" |
47 |
}
|
48 |
},
|
49 |
{
|
50 |
name: "Density (P/Km²)", |
51 |
color: "#FF404E", |
52 |
type: "spline", |
53 |
data: data[2], |
54 |
yAxis: 1 |
55 |
}
|
56 |
],
|
57 |
tooltip: { |
58 |
shared: true |
59 |
},
|
60 |
legend: { |
61 |
backgroundColor: "#ececec", |
62 |
shadow: true |
63 |
},
|
64 |
credits: { |
65 |
enabled: false |
66 |
},
|
67 |
noData: { |
68 |
style: { |
69 |
fontSize: "16px" |
70 |
}
|
71 |
}
|
72 |
});
|
73 |
}
|
Не пугайтесь кода выше! Без сомнений, лучшим способом понять, как он работает, является практика. Также вам определенно стоит почитать документацию. Тем не менее, давайте подчеркнем основные моменты:
- По оси Х у нас расположены страны.
- Мы устанавливаем две оси Y. По одной у нас имеются значения численности населения, по другой - все доступные значения плотности населения.
- При отсутствии данных графика появляется соответствующее сообщение. Заметьте, что мы можем настраивать текст сообщения при помощи объекта
lang.
После построения графиков давайте снова посмотрим на наш прогресс:
Синхронизация таблицы и графиков
В предыдущем разделе мы построили график на основе данных таблицы. Но до сих пор мы не достигли полной синхронизации между таблицей и графиком. Если хотите убедиться, то вернитесь назад к нашей предыдущей демоверсии и измените порядок следования строк таблицы (сортировку) или выполните поиск чего-нибудь. Вы заметете, что график не реагирует на изменения в таблице.
Чтобы это исправить, мы воспользуемся событием draw библиотеки DataTables. Это событие генерируется каждый раз, когда обновляется таблица. Поэтому, как только мы изменяем таблицу, нам необходимо заново извлечь данные таблицы и вновь построить график.
Однако, есть подвох. Событие draw также генерируется при переходе по страницам таблицы. Нет смысла перестраивать график в это время. В идеале нам следует предотвратить это поведение. К счастью, имеется событие page, при помощи которого мы можем это осуществить.
Ниже приводится код для реализации требуемой функциональности.
1 |
let draw = false; |
2 |
|
3 |
function setTableEvents(table) { |
4 |
// listen for page clicks
|
5 |
table.on("page", () => { |
6 |
draw = true; |
7 |
});
|
8 |
|
9 |
// listen for updates and adjust the chart accordingly
|
10 |
table.on("draw", () => { |
11 |
if (draw) { |
12 |
draw = false; |
13 |
} else { |
14 |
const tableData = getTableData(table); |
15 |
createHighcharts(tableData); |
16 |
}
|
17 |
});
|
18 |
}
|
Теперь, когда таблица и график синхронизированы, при выполнении «неправильного» поискового запроса (* запрос данных, которых нет в таблице) мы увидим следующие сообщения:



Вот наша окончательная версия проекта:
Поддержка браузерами
Оба плагина отлично поддерживаются браузерами (поддержка DataTables, поддержка Highcharts). Поэтому вы можете ожидать, что эта демоверсия будет хорошо работать во всех недавно вышедших версиях браузеров.
Опять-таки помните, что эта демо не оптимизирована для устройств с маленьким экраном.
В заключение, как обычно, мы используем Babel (* транспилятор) для компиляции кода, соответствующего спецификации ES6, в код, соответствующий стандарту ES5.
Вывод
Вот и все, чуваки! Мы сумели визуализировать наши данные при помощи совместного использования двух популярных и мощных библиотек JavaScript.
Теперь, когда вы знакомы с процессом, давайте, усовершенствуйте функциональные возможности финальной демоверсии. Например, попробуйте добавить к таблице пользовательские фильтры.
Как всегда, если у вас имеются вопросы или хотели бы увидеть какое-то продолжение руководства, дайте мне знать в комментариях ниже.



