[Перевод] Создание карты потоков с помощью JavaScript: пошаговое руководство
Карты потоков — это мощный способ представления движения объектов между различными географическими локациями, который очень легко реализуется с помощью JavaScript. По сути, они совмещают в себе функциональность карты и потоковой диаграммы. Такой тип визуализации показывает направление движения людей, товаров, денег или информации, а также их количество.
В текущем руководстве мы познакомим вас с процессом создания карты потоков. А чтобы сделать этот процесс более практичным, мы используем пример визуализации количества студентов из Индии, обучающихся в разных странах. Следуя этому руководству, вы научитесь создавать собственные карты потоков с помощью JS для любых видов данных.
Превью карты
Ниже вы можете видеть, как будет выглядеть наша итоговая карта потоков.
Создание базовой карты потоков с помощью JavaScript
С помощью JS построить карту потоков можно в четыре основных шага:
- Создать веб-страницу с помощью HTML.
- Включить необходимые файлы JS.
- Добавить данные.
- Написать JS-код для отрисовки графика.
Наличие хорошего понимания HTML, CSS и JS будет весьма кстати, но не стоит беспокоиться, если эти инструменты для вас малознакомы. В данном руководстве я подробно опишу каждый шаг, максимально упростив для вас задачу.
▍ 1. Создание веб-страницы на HTML
Чтобы карта потоков отображалась на всю страницу, мы с помощью CSS установим высоту и ширину Проще и быстрее всего создать интерактивную карту потоков можно с помощью графической библиотеки JS. Однако не все библиотеки поддерживают такую возможность. Для этого руководства мы будем использовать JS Charts, которая, помимо поддержки карт потоков, также имеет прекрасную документацию по картированию и множество готовых примеров. Для создания карты нам нужно добавить несколько модулей AnyChart: модули Core и Geo Map для визуализации данных, а также geodata для карты. Для обработки географических координат мы используем библиотеку Proj4js, так что она тоже включена. Кроме того, для добавления в UI возможности масштабирования нам потребуется AnyChart модуль Common UI и CSS. Чтобы отобрать 10 ведущих стран, я проанализировал данные и на основе количества учащихся в них студентов выбрал следующие: Австралия, Канада, Германия, Оман, Катар, Российская Федерация, Саудовская Аравия, Объединённые Арабские Эмираты, Великобритания и США. При создании карты потоков в качестве конечных точек следования учащихся мы будем использовать столицы этих стран, а в качестве отправной — Нью Дели, Индия. Координаты широты и долготы столиц я определял с помощью сайта LatLong.net. В таблице ниже показан список выбранных стран, а также общее число обучающихся в них студентов из Индии и координаты столиц. Прежде чем начать, нужно убедиться, что наш код выполняется всего раз, и страница загружается полноценно. Сделаем мы это с помощью функции И это совсем несложно — потребуется всего три дополнительные строчки кода. Взгляните на её интерактивную версию и поиграйтесь с ней в песочнице AnyChart. Вот весь исходный код: Далее мы внесём в код ряд простых изменений, чтобы добавить в карту дополнительные возможности и опции кастомизации. Таким образом, мы повысим интерес пользователей и преподнесём информацию более эффективно. Чтобы это исправить, можно изменить датасет, добавив в него свойство Один из вариантов — это показывать в справке название целевой страны и общее число студентов. Так, пользователи смогут легко понять представленную информацию и лучше сориентироваться на карте. Для этого мы изменим создающий линии код, и применим к ним новый цвет с помощью функций Для этого мы сначала сгруппируем страны в четыре категории, исходя из общего числа обучающихся в них студентов. Вот весь код карты: Успехов!
Для начала создадим простую HTML-страницу в качестве контейнера для отображения нашей карты. Сделаем мы это путём создания элемента id
на container
. Это позволит позднее обращаться к созданному контейнеру, когда мы добавим карту.
▍ 2. Добавление необходимых файлов JavaScript
Далее мы добавим в раздел шапки нашего HTML-файла необходимые скрипты для построения карты потоков.
▍ 3. Добавление данных
В этом руководстве мы будем визуализировать Топ-10 стран, в которые направлялись студенты из Индии в 2022 году. Источником данных здесь выступает индийское Министерство иностранных дел, которое предоставляет информацию по количеству студентов, обучающихся за рубежом.
Далее приводится датасет, который мы будем использовать для создания карты потоков. Он представляет собой массив объектов, каждый из которых отражает одно направление потока. Для всех объектов указаны широта и долгота отправной и конечной точек, а также название целевой страны и количество обучающихся в ней студентов.var data = [
{ points: [28.610198, 77.207584, -30.59, 145.94], to: "Australia", total: 100009 },
{ points: [28.610198, 77.207584, 45.41, -75.69], to: "Canada", total: 183310 },
{ points: [28.610198, 77.207584, 52.51, 13.40], to: "Germany", total: 34864 },
{ points: [28.610198, 77.207584, 23.58, 58.38], to: "Oman", total: 39550 },
{ points: [28.610198, 77.207584, 25.28, 51.53], to: "Qatar", total: 46000 },
{ points: [28.610198, 77.207584, 55.74, 37.62], to: "Russian Federation", total: 18039 },
{ points: [28.610198, 77.207584, 24.71, 46.67], to: "Saudi Arabia", total: 65800 },
{ points: [28.610198, 77.207584, 24.45, 54.37], to: "United Arab Emirates", total: 164000 },
{ points: [28.610198, 77.207584, 52.66, -0.95], to: "United Kingdom", total: 55465 },
{ points: [28.610198, 77.207584, 38.88, -77.03], to: "United States", total: 465791 }
];
▍ 4. Написание JS-кода для отрисовки карты
Теперь, когда данные подготовлены, пора перейти к основной части — размещению карты потоков на веб-странице.anychart.onDocumentReady()
, которая включит весь код карты потоков.
Далее мы добавим данные, которые подготовили на первом этапе.anychart.onDocumentReady(function () {
var data = [
{ points: [28.610198, 77.207584, -30.59, 145.94], to: "Australia", total: 100009 },
{ points: [28.610198, 77.207584, 45.41, -75.69], to: "Canada", total: 183310 },
{ points: [28.610198, 77.207584, 52.51, 13.40], to: "Germany", total: 34864 },
{ points: [28.610198, 77.207584, 23.58, 58.38], to: "Oman", total: 39550 },
{ points: [28.610198, 77.207584, 25.28, 51.53], to: "Qatar", total: 46000 },
{ points: [28.610198, 77.207584, 55.74, 37.62], to: "Russian Federation", total: 18039 },
{ points: [28.610198, 77.207584, 24.71, 46.67], to: "Saudi Arabia", total: 65800 },
{ points: [28.610198, 77.207584, 24.45, 54.37], to: "United Arab Emirates", total: 164000 },
{ points: [28.610198, 77.207584, 52.66, -0.95], to: "United Kingdom", total: 55465 },
{ points: [28.610198, 77.207584, 38.88, -77.03], to: "United States", total: 465791 }
];
});
Для создания графика карты потоков мы используем AnyChart функцию connector()
, передав ей данные для соединительных линий и включив геоданные карты мира.var map = anychart.connector();
var connectorSeries = map.connector(data);
map.geoData(anychart.maps.world);
Далее мы установим метки и добавим стрелочки в конец линии каждого потока.connectorSeries
.labels()
.enabled(true)
.position('100%')
.format(function () {
return this.getData('to')
});
connectorSeries
.markers()
.position('100%')
.size(12);
Теперь нужно указать для нашей карты потоков заголовок.map.title("Top 10 Destination Countries for Indian Students Studying Abroad");
Наконец, мы сошлёмся на ID контейнера, поместим карту в элемент container
и отобразим его на странице с помощью функции draw()
.map.container('container');
map.draw();
Этого должно быть достаточно, для отображения нашей карты потоков на веб-странице. Однако, поскольку мы работаем с картой мира, будет нелишним для удобства пользователей добавить возможность изменения масштаба.var zoomController = anychart.ui.zoom();
zoomController.target(map);
zoomController.render();
Вот и всё! Наша базовая карта потоков готова.
Кастомизация
Отличная работа! Создавать простые интерактивные карты потоков с помощью JS действительно не так уж сложно. Теперь перейдём к следующим шагам, чтобы улучшить и персонализировать нашу карту, сделав её более информативной и привлекательной.▍ A. Оптимизация кривых линий и позиций меток
В нашей карте потоков информация об учащихся в 10 странах индийских студентах представлена соединительными линиями. Однако при используемых нами данных предустановленные настройки ведут к наложению линий, и некоторые названия стран оказываются невидны, пока их не приблизишь.curvature
, которое позволит скорректировать кривизну отдельных линий. Помимо этого, мы добавим свойство label
и установим его значения, чтобы метки отображались в нужных точках карты.var data = [
{ points: [28.610198, 77.207584, -30.592659, 145.943667], to: "Australia", total: 100009, curvature: 0.5 },
{ points: [28.610198, 77.207584, 45.411673, -75.69629], to: "Canada", total: 183310, curvature: 0.8, label: { offsetY: -30 } },
{ points: [28.610198, 77.207584, 52.511693, 13.403121], to: "Germany", total: 34864, curvature: 0.3, label: { anchor: 'center-top', offsetY: -2 } },
{ points: [28.610198, 77.207584, 23.5880, 58.3829], to: "Oman", total: 39550, curvature: -0.5, label: { anchor: 'left-top' } },
{ points: [28.610198, 77.207584, 25.2854, 51.5310], to: "Qatar", total: 46000, curvature: 0.4, label: { anchor: 'right-top', offsetY: -20 } },
{ points: [28.610198, 77.207584, 55.747362, 37.621273], to: "Russian Federation", total: 18039, curvature: 0.4, label: { anchor: 'left-bottom' } },
{ points: [28.610198, 77.207584, 24.710437, 46.675164], to: "Saudi Arabia", total: 65800, curvature: 0.7, label: { offsetY: -5 } },
{ points: [28.610198, 77.207584, 24.4539, 54.3773], to: "United Arab Emirates", total: 164000, curvature: 0, label: { anchor: 'left-top', offsetY: -15 } },
{ points: [28.610198, 77.207584, 52.667078, -0.955920], to: "United Kingdom", total: 55465, curvature: 0.4, label: { anchor: 'right-top', offsetY: -25, offsetX: -10 } },
{ points: [28.610198, 77.207584, 38.884053, -77.033513], to: "USA", total: 465791, curvature: -0.6 },
];
Благодаря этим изменениям, теперь можно отображать метки даже в случае их наложения. Реализовать это можно одной строкой кода.map.overlapMode("allow-overlap");
▍ B. Доработка справочной информации
Сейчас в справке карты показывается широта и долгота, которые особого смысла не имеют. Чтобы повысить её информативность, мы отобразим более значимую информацию.connectorSeries
.tooltip()
.useHtml(true)
.format(function () {
return (
'
To: ' + this.getData('to') + '
' +
'Total Students: ' + this.getData('total').toLocaleString() + '
'
);
});▍ C. Доработка заголовка
Чтобы повысить привлекательность заголовка нашей карты, можно выделить его при помощи HTML-стилизации, чтобы он был более заметен и привлекал внимание.map.title()
.enabled(true)
.useHtml(true)
.text(
'Top 10 Destination Countries for Indian Students Studying Abroad
' +
'The top destination is the U.S.'
);▍ D. Выбор цветов для соединительных линий и маркеров
Для внесения некоторых эстетических изменений можно заменить базовый цвет линий градиентным, который будет плавно переходить от красного в жёлтый.fill()
и stroke()
.var connectorSeries = map.connector(data)
.fill(['#e8dd09', 'red'])
.stroke(['#e8dd09', 'red']);
connectorSeries
.hovered()
.stroke('#808080')
.fill('#808080');
connectorSeries
.hovered()
.markers()
.stroke('#808080')
.fill('#808080');
После этого изменения карта будет выглядеть более привлекательной и интересной. Хотя если вам больше по нраву другие цвета, то можете поэкспериментировать с разными их комбинациями.▍ E. Изменение цвета и толщины линий на основе данных
На заключительном этапе кастомизации мы сделаем соединительные линии более интересными, изменив их цвета и толщину на основе количества студентов, а также добавим легенду для лучшего понимания.
Мы также создадим filter_function()
, которая будет фильтровать данные согласно этим категориям.function filter_function(val1, val2) {
if (val2)
return function (fieldVal) {
return val1 <= fieldVal && fieldVal < val2;
};
else
return function (fieldVal) {
return val1 <= fieldVal;
};
}
Далее мы создадим функцию createSeries()
, которая будет получать датасеты и конфигурации, создавая на их основе соединительные линии.function createSeries(data, name, color, size) {
// Создание соединительных линий.
var connectorSeries = map.connector(data)
.name(name)
.fill(color)
.stroke(color)
.color(color);
connectorSeries
.hovered()
.stroke('#808080')
.fill('#808080');
connectorSeries
.hovered()
.markers()
.stroke('#808080')
.fill('#808080');
// Установка меток для линий.
connectorSeries
.labels()
.enabled(true)
.position('100%')
.fontColor('#2D2D2D')
.format(function () {
return this.getData('to')
});
// Установка стрелочек в конце линий.
connectorSeries
.markers()
.position('100%')
.size(12);
// Настройка справочной информации для линий.
connectorSeries
.tooltip()
.useHtml(true)
.format(function () {
return (
'
To: ' + this.getData('to') + '
' +
'Total Students: ' + this.getData('total').toLocaleString() + '
'
);
});
// Установка толщины линии, исходя из количества студентов.
connectorSeries
.startSize(size[0])
.endSize(size[1]);
}
Мы также создадим из наших данных датасет.var dataSet = anychart.data.set(data).mapAs();
После чего отфильтруем его с помощью filter_function()
и передадим в функцию createSeries()
для создания набора линий.createSeries(dataSet.filter('total', filter_function(0, 50000)), 'Less than 50,000', '#A149FA', [1, 0]);
createSeries(dataSet.filter('total', filter_function(50000, 100000)), '50,000 - 100,000', '#3B44F6', [2, 1]);
createSeries(dataSet.filter('total', filter_function(100000, 200000)), '100,000 - 200,000', '#3EC70B', [4, 1]);
createSeries(dataSet.filter('total', filter_function(200000, 500000)), 'More than 200,000', '#F7EC09', [6, 1]);
Наконец, мы добавим для нашей карты потоков легенду, которая поможет пользователям понять, что означают цвета и толщина соединительных линий.map.legend().enabled(true).position('bottom').padding([20, 0, 0, 0]).fontSize(10);
map.legend().title().enabled(true).text('Number of Students').fontSize(13).padding([0, 0, 5, 0]);
Итак, цель достигнута! Мы создали прекрасную интерактивную карту потоков с помощью JS.
В результате мы видим, что цвета и толщина соединительных линий варьируются на основе количества студентов. Конечную интерактивную версию этой карты можно просмотреть в песочнице AnyChart. Вы также можете внести в код дополнительные изменения и поэкспериментировать с ним.
Заключение
Создавать карты потоков с помощью JavaScript легко и интересно. Рекомендую ознакомиться с другими примерами карт и соединительных линий, из которых вы сможете почерпнуть идеи для собственной карты.Telegram-канал с розыгрышами призов, новостями IT и постами о ретроиграх