Статьи

Визуализация данных с помощью DataTables.js и Highcharts.js

В этом руководстве вы узнаете, как визуализировать данные, используя библиотеки JavaScript DataTables.js и Highcharts.js .

Вот то, что мы собираемся построить (посмотрите увеличенную версию для лучшего опыта):

Для целей этого примера нам потребуется загрузить следующие библиотеки в наше перо:

  • JQuery
  • DataTables.js
  • Highcharts.js

Имея это в виду, если вы посмотрите на вкладку « Настройки », вы увидите, что я включил один внешний файл CSS:

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

Примечание: нам пришлось добавить jQuery в наш проект, потому что DataTables.js — это плагин jQuery. Однако имейте в виду, что Highcharts.js является чистой библиотекой JavaScript и поэтому не требует jQuery.

Для начала определим элемент с классом container который содержит два подэлемента:

  • Стол с 26 строками. Первая строка ссылается на заголовки таблицы th , а остальные 25 строк содержат информацию о стране. Источником наших данных для этого примера является worldometer.info .
  • Пустой div который будет содержать график.

Вот структура HTML:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<div class=»container»>
  <table id=»dt-table»>
    <thead>
      <tr>
        <th>Country</th>
        <th>Population (2017)</th>
        <th>Density (P/Km²)</th>
        <th>Med.
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>China</td>
        <td>1,409,517,397</td>
        <td>150</td>
        <td>37</td>
      </tr>
     
      <!— 24 more rows here —>
    
    </tbody
  </table>
   
  <div id=»chart»></div>
</div>

Стоит отметить, что для простоты мы указали вышеупомянутые жестко закодированные данные таблиц. В реальном проекте таблица может быть создана динамически.

С готовой разметкой и добавленным цветом фона для наглядности проект выглядит следующим образом:

На этом этапе мы определяем некоторые основные стили, например:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
.container {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  padding: 0 10px;
}
 
#dt-table_wrapper {
  width: 35%;
  margin-right: 2%;
}
 
#chart {
  width: 63%;
}
 
table {
  text-align: left;
}
 
@media screen and (max-width: 1200px) {
  #dt-table_wrapper,
  #chart {
    width: 100%;
  }
 
  #dt-table_wrapper {
    margin-right: 0;
  }
}

Важно понимать, что:

  • #dt-table_wrapper не существует в нашей разметке. Он добавляется в DataTables, как только мы его инициализируем.
  • Хотя мы определили несколько основных правил для небольших экранов, обратите внимание, что демонстрация не будет полностью адаптивной. Есть много вещей, которые мы можем сделать, чтобы таблица и диаграмма выглядели лучше на маленьких экранах. Например, для DataTables доступно расширение Responsive , но оно выходит за рамки данного руководства.

С CSS на месте, давайте посмотрим, как выглядит проект. Мы пока не увидим большой разницы, потому что мы не инициализировали библиотеки:

Теперь для окна JavaScript в нашей ручке. Когда DOM готов, функция init выполняется; эта функция запускает другие подфункции:

1
2
3
4
5
6
function init() {
  const table = $(«#dt-table»).DataTable();
  const tableData = getTableData(table);
  createHighcharts(tableData);
  setTableEvents(table);
}

Как вы увидите, каждая из этих подфункций выполняет определенную задачу.

Первым шагом является преобразование нашей таблицы в таблицу «DataTables». Мы можем сделать это всего одной строкой кода: $("#dt-table").DataTable();

Если мы теперь посмотрим на таблицу, то заметим, что она приняла возможности таблицы DataTables, то есть: мы можем ее отсортировать, выполнить поиск и так далее. Поиграйте с ним в следующем демо:

Теперь, как вы можете видеть, DataTables применяет сортировку по умолчанию к таблице. При необходимости мы можем настроить это поведение.

Следующим шагом является сбор данных таблицы и построение диаграммы. Нам не нужны все данные таблицы. Фактически, если вы посмотрите на законченную версию нашей демонстрации, вы заметите, что диаграмма содержит данные только из первых трех столбцов (Страна, Население, Плотность).

Учитывая это, для извлечения необходимых данных мы воспользуемся API-интерфейсом DataTables . Функция, ответственная за это поведение, следующая:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
function getTableData(table) {
  const dataArray = [],
    countryArray = [],
    populationArray = [],
    densityArray = [];
 
  // loop table rows
  table.rows({ search: «applied» }).every(function() {
    const data = this.data();
    countryArray.push(data[0]);
    populationArray.push(parseInt(data[1].replace(/\,/g, «»)));
    densityArray.push(parseInt(data[2].replace(/\,/g, «»)));
  });
 
  // store all data in dataArray
  dataArray.push(countryArray, populationArray, densityArray);
 
  return dataArray;
}

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

Вот быстрая визуализация массива master (т.е. dataArray ):

Массив, содержащий нужные данные таблицы

Прежде чем двигаться дальше, важно понять одну вещь. По умолчанию функция getTableData должна собирать данные из всех строк таблицы. Но затем, если мы ищем в таблице что-то конкретное, должны быть собраны и обработаны только соответствующие строки. Для достижения этой цели мы передаем аргумент функции rows . В частности, объект с search: "applied" значение свойства.

Еще раз обратите внимание, что если мы не передадим этот объект, мы всегда будем собирать данные из всех строк таблицы (проверить это). Для получения дополнительной информации о свойствах, которые мы можем передать этому объекту, обязательно посмотрите эту страницу .

Теперь, когда у нас есть нужные данные, мы готовы построить график. Он будет содержать две вложенные диаграммы, одну столбцовую диаграмму и одну сплайн-диаграмму .

Вот соответствующая функция:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
function createHighcharts(data) {
  Highcharts.setOptions({
    lang: {
      thousandsSep: «,»
    }
  });
 
  Highcharts.chart(«chart», {
    title: {
      text: «DataTables to Highcharts»
    },
    subtitle: {
      text: «Data from worldometers.info»
    },
    xAxis: [
      {
        categories: data[0],
        labels: {
          rotation: -45
        }
      }
    ],
    yAxis: [
      {
        // first yaxis
        title: {
          text: «Population (2017)»
        }
      },
      {
        // secondary yaxis
        title: {
          text: «Density (P/Km²)»
        },
        min: 0,
        opposite: true
      }
    ],
    series: [
      {
        name: «Population (2017)»,
        color: «#0071A7»,
        type: «column»,
        data: data[1],
        tooltip: {
          valueSuffix: » M»
        }
      },
      {
        name: «Density (P/Km²)»,
        color: «#FF404E»,
        type: «spline»,
        data: data[2],
        yAxis: 1
      }
    ],
    tooltip: {
      shared: true
    },
    legend: {
      backgroundColor: «#ececec»,
      shadow: true
    },
    credits: {
      enabled: false
    },
    noData: {
      style: {
        fontSize: «16px»
      }
    }
  });
}

Не удивляйтесь приведенному выше коду! Без сомнения, лучший способ понять, как это работает, это попробовать. Кроме того, вы обязательно должны прочитать документацию . В любом случае, давайте кратко остановимся на ключевых понятиях:

  • Ось X содержит все страны.
  • Мы определяем две оси Y. Первый содержит все значения совокупности, а второй — все доступные плотности.
  • Если наш график не содержит никаких данных, появляется сообщение. Обратите внимание, что мы можем настроить текст сообщения с помощью объекта lang .

С диаграммами на месте, давайте снова посмотрим на наш прогресс:

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

Чтобы исправить это, мы воспользуемся событием draw DataTables. Это событие срабатывает каждый раз, когда таблица обновляется. Поэтому, как только мы изменим таблицу, мы должны вспомнить данные таблицы и восстановить диаграмму.

Вот хитрая вещь, хотя. Событие draw также происходит во время нумерации таблиц; нет причин перестраивать график во время этого процесса. В идеале, мы должны предотвратить это поведение. К счастью, есть событие page которое помогает нам выполнить эту задачу.

Вот код, который реализует желаемую функциональность:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
let draw = false;
 
function setTableEvents(table) {
  // listen for page clicks
  table.on(«page», () => {
    draw = true;
  });
 
  // listen for updates and adjust the chart accordingly
  table.on(«draw», () => {
    if (draw) {
      draw = false;
    } else {
      const tableData = getTableData(table);
      createHighcharts(tableData);
    }
  });
}

Теперь, когда таблица и диаграмма синхронизированы, если мы выполним «плохой» поиск, мы увидим следующие сообщения:

Финальная версия нашего проекта:

Оба плагина имеют отличную поддержку браузера (поддержка DataTables, поддержка Highcharts ), поэтому вы можете ожидать, что эта демонстрация будет хорошо работать во всех последних браузерах.

Снова имейте в виду, что это демо не оптимизировано для маленьких экранов.

Наконец, как обычно, мы используем Babel для компиляции кода ES6 до ES5.

Вот и все, ребята! Нам удалось визуализировать наши данные, объединив две популярные и мощные библиотеки JavaScript.

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

Как всегда, если у вас есть какие-либо вопросы или есть что-то еще, что вы хотели бы видеть в качестве следующего шага к этому уроку, дайте мне знать в комментариях ниже.