Как построить COVID‑трекер на JavaScript и billboard.js
Что вы построите
Этот материал шаг за шагом объясняет базовый рабочий цикл: запрос данных из внешнего API, преобразование JSON в формат, пригодный для графика, и отрисовку интерактивной диаграммы с помощью billboard.js. Подойдёт как учебный проект для практики Fetch API, работы с массивами и простых конфигураций графиков.
Важно: весь код можно поместить в простой статический сайт — никакой серверной логики для этого примера не требуется.
Источник данных и почему disease.sh
Для получения актуальных данных мы используем disease.sh — открытый API с данными о COVID. Он удобен для учебных проектов, потому что:
- возвращает JSON (удобный для JavaScript);
- не требует авторизации и ключей;
- агрегирует данные из разных источников и предоставляет несколько энтпойнтов;
- достаточно подробно документирован (см. официальный сайт disease.sh для справки).
Для демонстрации в этом руководстве мы используем исторические данные New York Times по США, которые в disease.sh представлены в виде массива объектов с датами и значениями по дням. Пример исходного вывода API:
Если вы знакомы с JSON, то такая структура понятна: массив объектов, где каждый объект содержит поля date, cases, deaths и т. п. Маленький фрагмент в читаемом виде:
[{
"date":"2020-01-21",
"cases":1,
"deaths":0,
"updated":1643386814538
},{
"date":"2020-01-22",
"cases":1,
"deaths":0,
"updated":1643386814538
}]Минимальный HTML‑каркас
Создадим простой HTML-файл, куда будем подключать JavaScript и место для графика:
Covid Tracker
Covid cases, US
Примечание: порядок подключений важен — billboard.js требует d3.js, а локальный скрипт должен быть подключён после библиотек.
Шаг 1 — получение данных (Fetch)
В файле covid.js начнём с простого запроса и вывода результата в консоль. Это поможет убедиться, что API доступен из браузера.
const api = 'https://disease.sh/v3/covid-19/nyt/usa';
fetch(api)
.then(response => {
if (!response.ok) throw new Error(`HTTP error ${response.status}`);
return response.json();
})
.then(data => {
console.log('Получены данные:', data);
})
.catch(err => console.error('Ошибка запроса:', err));Ключевые моменты:
- Проверяйте response.ok, чтобы обработать HTTP‑ошибки.
- Используйте .catch для вывода сетевых/парсерных ошибок.
Шаг 2 — подготовка данных для графика
billboard.js ожидает данные в определённом формате: массивы столбцов, где первый элемент массива — название серии (или меток оси X). Для временного ряда удобно подготовить две колонки: даты и значения случаев.
function plotData(data) {
// data — массив объектов {date, cases, deaths, ...}
const keys = data.map(a => a.date);
const cases = data.map(a => a.cases);
keys.unshift('dates'); // теперь keys = ['dates', '2020-01-21', ...]
cases.unshift('cases'); // cases = ['cases', 1, 2, ...]
// конфигурация графика дальше
}Шаг 3 — базовый график billboard.js
Добавим в plotData генерацию простого линейного графика:
function plotData(data) {
const keys = data.map(a => a.date);
const cases = data.map(a => a.cases);
keys.unshift('dates');
cases.unshift('cases');
bb.generate({
bindto: '#covid-all-us-cases',
data: {
x: 'dates',
type: 'line',
columns: [keys, cases]
},
axis: {
x: {
type: 'category',
tick: { count: 10 }
}
}
});
}Эта конфигурация связывает массив дат с осью X (x: ‘dates’), задаёт тип графика line и ограничивает количество отметок на оси X до 10.
Полный рабочий поток вместе
Комбинируем fetch и визуализацию:
const api = 'https://disease.sh/v3/covid-19/nyt/usa';
fetch(api)
.then(r => { if (!r.ok) throw new Error(r.status); return r.json(); })
.then(data => plotData(data))
.catch(err => console.error(err));
function plotData(data) {
const keys = data.map(a => a.date);
const cases = data.map(a => a.cases);
keys.unshift('dates');
cases.unshift('cases');
bb.generate({
bindto: '#covid-all-us-cases',
data: {
x: 'dates',
type: 'line',
columns: [keys, cases]
},
axis: {
x: {
type: 'category',
tick: { count: 10 }
}
}
});
}Вариации визуализаций и работы с объёмом данных
В реальных задачах график за несколько лет получается «захламлённым». Ниже — три простых приёма, как упростить видимость данных, не теряя информативности.
1) Ограничение временного интервала (например, один год)
Если нужно показать только 2022 год, примените фильтр перед передачей данных в plotData:
fetch(api)
.then(r => r.json())
.then(data => plotData(data.filter(a => a.date > '2022')));Здесь используется строковое сравнение дат в формате YYYY-MM-DD, что корректно для такой сортировки.
2) Уменьшение детализации (например, одна точка в неделю)
Чтобы взять каждую 7‑ю запись (выборка по интервалу), используйте индекс в filter:
plotData(data.filter((a, i) => i % 7 === 0));3) Несколько серий на одном графике (cases и deaths)
Добавим ещё одну серию и отрисуем её вместе с первой, настроив разные оси и типы отображения:
function plotData(data) {
const dates = data.map(a => a.date);
const cases = data.map(a => a.cases);
const deaths = data.map(a => a.deaths);
dates.unshift('dates');
cases.unshift('cases');
deaths.unshift('deaths');
bb.generate({
bindto: '#covid-all-us-cases',
data: {
x: 'dates',
columns: [dates, cases, deaths],
axes: { cases: 'y', deaths: 'y2' },
types: { cases: 'bar', deaths: 'line' }
},
axis: {
x: { type: 'category', tick: { count: 10 } },
y2: { show: true }
}
});
}Когда это решение не подходит (ограничения и ошибки)
- CORS: если API не выставляет заголовки CORS, браузер заблокирует запросы. Решение: проксировать запрос через ваш сервер.
- Ограничения API: публичные API могут иметь rate limit — при большом числе пользователей потребуется кэширование или серверная промежуточная прослойка.
- Большие объёмы данных: если данных слишком много (тысячи точек), визуализация в браузере может быть медленной. Решения: агрегация на сервере, разбиение данных по страницам, использование WebGL‑решений.
- Достоверность данных: источники могут иметь задержки и корректировки — для ответственных приложений проверяйте даты обновления и источник.
Альтернативные библиотеки и подходы
- Chart.js — широко используемая библиотека проще в настройке для большинстве базовых графиков.
- D3.js — мощный инструмент для кастомных визуализаций, но требует больше кода.
- Plotly.js — хороший выбор, если нужны экспорт и богатые взаимодействия.
- Google Charts — быстрый старт с простым подключением для базовых случаев.
Выбор зависит от требований: если нужен быстрый прототип — billboard.js или Chart.js; для кастомных интерактивных виджетов — D3.
Практические подсказки и шаблоны (cheat sheet)
- Проверка успешного получения данных:
if (!Array.isArray(data)) throw new Error('Ожидался массив объектов');- Быстрая агрегация по неделям (пример):
function aggregateWeekly(data) {
return data.filter((_, i) => i % 7 === 0);
}- Переход от категорий к временной оси: billboard.js поддерживает тип x: ‘timeseries’ и парсинг дат, если вам нужны аккуратные метки времени.
// пример для timeseries
bb.generate({
data: { x: 'x', columns: [['x', '2020-01-21', '2020-01-22'], ['data', 1, 1]] },
axis: { x: { type: 'timeseries', tick: { format: '%Y-%m-%d' } } }
});- Отладка: используйте консоль браузера и выводы console.table для быстрого просмотра структурированных данных.
Критерии приёмки
- Данные загружаются без ошибок и отображаются в консоли;
- Диаграмма отрисовывается в контейнере #covid-all-us-cases;
- При переключении фильтров (год, агрегация) график обновляется корректно;
- При объединении нескольких серий оси и легенда читаемы.
Роль‑ориентированные чек‑листы
Для разработчика фронтенда:
- проверить CORS и механизмы кэширования;
- убедиться, что зависимости подключены в корректном порядке;
- покрыть кейсы с пустыми и частично заполненными данными.
Для дизайнера/UX:
- проверить читаемость осей и легенды;
- предусмотреть подсказки при наведении;
- обеспечить доступность (контраст, крупный шрифт).
Для DevOps/владельца продукта:
- настроить мониторинг доступности API и алерты на ошибки;
- организовать кэширование и балансировку запросов при росте трафика.
Безопасность, приватность и соответствие требованиям
- Приватность: если вы собираете пользовательские данные или логи запросов, убедитесь в соответствии с местными законами о защите данных (например, GDPR). Для публичного отображения агрегированных данных это обычно неактуально, но при сохранении IP‑адресов пользователей или их действий — нужна политика хранения данных.
- Безопасность: не храните чувствительные ключи в коде, даже если сейчас API публично открыт. При переходе к защищённым API используйте серверную прослойку для сокрытия секретов.
Производительность и масштабирование
- Кэширование: кешируйте ответ API на стороне сервера или CDN, чтобы снизить нагрузку и ускорить отклик.
- Ленивая загрузка: загружайте большие наборы данных по требованию (например, при выборе периода).
- Агрегация: агрегируйте данные по дням/неделям/месяцам на сервере для долгих временных рядов.
Тесты и приёмка
Набор минимальных тестов:
- unit: функции map/reduce/aggregate возвращают ожидаемые результаты на фиксированных входных данных;
- integration: при эмуляции успешного API-ответа график отрисовывается в DOM;
- e2e: пользователь может выбрать год и увидеть изменённый график.
Отладочный план (runbook)
- Если график не отрисовывается — проверить консоль на ошибки (CORS, 404, парсинг JSON).
- Если данные пустые — проверить endpoint вручную в браузере или через curl.
- Если график тормозит — уменьшить количество точек и проверить время отрисовки; включить профилирование в DevTools.
Методология быстрого прототипа (mini‑method)
- Получить и отобразить JSON в консоли — убедиться в структуре.
- Написать простую функцию plotData с заглушкой (пара массивов) и убедиться, что billboard.js работает.
- Подключить реальные данные и преобразовать в формат columns.
- Добавить фильтры/агрегации и тесты принятия.
Сравнение: когда выбирать billboard.js
- Используйте billboard.js, если вам нужен быстрый прототип с D3‑подложкой и небольшим объёмом кастомизации.
- Выберите Chart.js для простоты настроек и широкой поддержки типов.
- Берите D3.js для полного контроля и сложных кастомных визуализаций.
Краткая глоссарий (одна строка на термин)
- API — интерфейс для получения данных из внешних систем.
- CORS — политика браузера, ограничивающая междоменные запросы.
- timeseries — временной ряд, данные упорядоченные по времени.
- Агрегация — объединение данных (например, по неделю/месяц).
Резюме
Вы использовали Fetch API для получения данных, преобразовали JSON в формат, понятный для billboard.js, и построили интерактивные графики. Вы также узнали простые приёмы фильтрации и агрегации, получили рекомендации по масштабируемости, тестированию и соответствию требованиям приватности. Этот проект можно расширять: добавить выбор страны, данные о вакцинации, сверку источников и экспорт графиков.
Похожие материалы
Отключить статус «Просмотрено» в Instagram
Как ответить на сообщение в Instagram
Добавить музыку в заметки Instagram
Как пользоваться Notes в Instagram
Видео-заметки в Instagram: как публиковать