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

Шаг за шагом мы будем визуализировать маршрут знаменитого древнего Шелкового пути. Мы начнем с разработки базовой карты коннектора JS за четыре шага, а затем внесем несколько изменений, чтобы она выглядела потрясающе. Начнем путешествие!

Предварительный просмотр карты соединителя

Вот предварительный просмотр того, как будет выглядеть окончательная карта соединителей на основе JavaScript для руководства.

Без лишних слов, давайте приступим к сопоставлению коннекторов!

Создание базовой карты коннектора JS

Логика создания карт соединителей с помощью JavaScript довольно проста. Весь путь можно разбить на четыре основных шага:

  1. Создайте HTML-страницу.
  2. Добавьте необходимые файлы JavaScript.
  3. Подготовьте и загрузите данные.
  4. Напишите код JS, чтобы нарисовать карту соединителя.

1. Создайте HTML-страницу

Прежде всего, где мы должны разместить нашу интерактивную карту соединителей? Давайте создадим простую HTML-страницу.

Тут же добавляем элемент блока HTML и присваиваем ему уникальный идентификатор. Затем мы устанавливаем объявление стиля в таблице стилей.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>JavaScript Connector Map</title>
    <style type="text/css">      
      html, body, #container { 
        width: 100%; 
        height: 100%; 
        margin: 0; 
        padding: 0; 
      } 
    </style>
  </head>
  <body>
    <div id="container"></div>
  </body>
</html>

В приведенном выше примере элемент блока — <div>. Его атрибут id установлен как «контейнер». Параметры width и height элемента равны 100%, что обеспечит отображение карты соединителя на весь экран.

2. Добавьте необходимые файлы JavaScript

Во-вторых, нам нужно указать все скрипты, которые будут использоваться для визуализации данных, в разделе <head>.

В большинстве случаев вы можете выбирать из широкого спектра библиотек диаграмм JavaScript для интерактивной визуализации данных в Интернете. У каждого есть свои плюсы и минусы, поэтому выбор всегда зависит от того, что именно, где и как вы хотите. Однако базовый подход для всех одинаков. В этом уроке для иллюстрации мы будем использовать JS-библиотеку построения диаграмм под названием AnyChart. Имеет карты коннекторов среди поддерживаемых типов диаграмм, подробную документацию и бесплатную версию.

Нам нужны модули Core и Geo Map для визуализации данных в виде карты коннектора, geodata для карты мира и библиотека Proj4js для заботы о географических координатах.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>JavaScript Connector Map</title>
    <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-core.min.js"></script>
    <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-map.min.js"></script>
    <script src="https://cdn.anychart.com/releases/8.11.0/geodata/custom/world/world.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.8.0/proj4.js"></script>
    <style type="text/css">      
      html, body, #container { 
        width: 100%; 
        height: 100%; 
        margin: 0; 
        padding: 0; 
      } 
    </style>
  </head>
  <body>
    <div id="container"></div>
    <script>
      // The JS connector map code will be written here.
    </script>
  </body>
</html>

3. Подготовьте и загрузите данные

В-третьих, давайте установим данные для нашей карты коннекторов на основе JavaScript.

Шелковый путь представлял собой серию маршрутов. Представим один из них, от Сианя до Венеции, пролегавший через города Ланьчжоу, Дуньхуан, Цьемо, Хотан, Кашгар, Мерв, Тегеран, Багдад, Антиохию и Афины.

На карте соединителей начальная и конечная точки каждой соединительной линии определяются с помощью их широты и долготы. Чтобы получить координаты упомянутых выше городов, мы можем использовать один из нескольких инструментов генератора координат. Я уже сверил их с LatLong.net. Вот список городов вдоль маршрута, которые будут визуализированы, с указанием их широты и долготы:

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

var dataSet = [    
  {points: [33.62, 113.34, 36.05, 103.79]},
  {points: [36.05, 103.79, 40.14, 94.66]},
  {points: [40.14, 94.66, 38.14, 85.52]},
  {points: [38.14, 85.52, 37.11, 79.91]},
  {points: [37.11, 79.91, 39.46, 75.99]},
  {points: [39.46, 75.99, 37.66, 62.16]},
  {points: [37.66, 62.16, 35.68, 51.38]},
  {points: [35.68, 51.38, 33.31, 44.36]},
  {points: [33.31, 44.36, 36.19, 36.16]},
  {points: [36.19, 36.16, 37.98, 23.72]},
  {points: [37.98, 23.72, 45.44, 12.31]}
];

Теперь всего несколько строк JS-кода, чтобы наша карта коннекторов заработала на веб-странице!

4. Напишите JS-код, чтобы нарисовать карту коннекторов.

В-четвертых, давайте соберем код JavaScript, который будет рисовать карту коннекторов.

В начале мы добавляем функцию anychart.onDocumentReady(), которая будет заключать в себе весь код сопоставления коннектора JS. Это гарантирует, что все внутри него будет выполняться только после загрузки HTML-страницы.

<script>
  anychart.onDocumentReady(function () {
    // The connector map code will be written here.
  });
</script>

Итак, мы добавляем данные, только что подготовленные на третьем шаге.

anychart.onDocumentReady(function () {
  var dataSet = [    
    {points: [33.62, 113.34, 36.05, 103.79]},
    {points: [36.05, 103.79, 40.14, 94.66]},
    {points: [40.14, 94.66, 38.14, 85.52]},
    {points: [38.14, 85.52, 37.11, 79.91]},
    {points: [37.11, 79.91, 39.46, 75.99]},
    {points: [39.46, 75.99, 37.66, 62.16]},
    {points: [37.66, 62.16, 35.68, 51.38]},
    {points: [35.68, 51.38, 33.31, 44.36]},
    {points: [33.31, 44.36, 36.19, 36.16]},
    {points: [36.19, 36.16, 37.98, 23.72]},
    {points: [37.98, 23.72, 45.44, 12.31]}
  ];
});

Все остальное входит в ту же объемлющую функцию. Мы создаем карту, используя функцию map(), затем серию карт коннектора, используя функцию connector() (и передавая в нее набор данных), и устанавливаем геоданные карты мира.

var map = anychart.map();
var series = map.connector(dataSet);
map.geoData(anychart.maps['world']);

Затем мы можем добавить заголовок, чтобы было понятно, что изображено на карте.

map.title("Silk Road Trade Route from Xian to Venice");

И последние две быстрые строки поместят карту в элемент контейнера и отобразят ее на странице.

map.container('container');
map.draw();

Ну вот! Наша карта коннекторов готова, и ее было довольно легко сделать, написав всего несколько строк кода!

Интерактивную версию этой базовой карты коннекторов JavaScript можно найти на JSFiddle [и на AnyChart Playground], где вы можете просмотреть код и поэкспериментировать с ним. Я также помещаю полный код ниже.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>JavaScript Connector Map</title>
    <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-core.min.js"></script>
    <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-map.min.js"></script>
    <script src="https://cdn.anychart.com/releases/8.11.0/geodata/custom/world/world.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.8.0/proj4.js"></script>
    <style type="text/css">      
      html, body, #container { 
        width: 100%; 
        height: 100%; 
        margin: 0; 
        padding: 0; 
      } 
    </style>
  </head>
  <body>
    <div id="container"></div>
    <script>
anychart.onDocumentReady(function () {
  // create a data set for connectors
  var dataSet = [    
    {points: [33.62, 113.34, 36.05, 103.79]},
    {points: [36.05, 103.79, 40.14, 94.66]},
    {points: [40.14, 94.66, 38.14, 85.52]},
    {points: [38.14, 85.52, 37.11, 79.91]},
    {points: [37.11, 79.91, 39.46, 75.99]},
    {points: [39.46, 75.99, 37.66, 62.16]},
    {points: [37.66, 62.16, 35.68, 51.38]},
    {points: [35.68, 51.38, 33.31, 44.36]},
    {points: [33.31, 44.36, 36.19, 36.16]},
    {points: [36.19, 36.16, 37.98, 23.72]},
    {points: [37.98, 23.72, 45.44, 12.31]}
  ];
  // create a map
  var map = anychart.map();
  // create a connector series
  var series = map.connector(dataSet);
  // set geodata
  map.geoData(anychart.maps['world']);
  // title the map
  map.title("Silk Road Trade Route from Xian to Venice");
  
  // set the container id
  map.container('container');
  // draw the map
  map.draw();
});
    </script>
  </body>
</html>

Настройка карты соединителя JavaScript

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

А. Масштабировать карту

Когда вы критически смотрите на базовую карту соединителей, первое, что вы можете заметить, это то, что так много места не используется. Серия разъемов охватывает территорию от Восточного Китая до Южной Европы.

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

var mapScale = map.scale();
mapScale.minimumX(30);
mapScale.maximumX(70);
mapScale.minimumY(0);
mapScale.maximumY(80);

B. Добавьте названия городов

У нас есть карта соединителей со стрелками по умолчанию от Сианя до Венеции, город за городом. Однако мне он кажется очень пустым, так как на карте нет названий городов.

Давайте добавим серию маркеров с названиями городов, заданных как новый массив объектов, где каждый объект имеет свойство имени, широты и долготы.

// create a data set for markers
var data_marker = [
  {"name": "Xian", "lat": 33.62, "long": 113.34},
  {"name": "Lanzhou", "lat": 36.05, "long": 103.79},
  {"name": "Dunhuang", "lat": 40.14, "long": 94.66},
  {"name": "Qiemo", "lat": 38.14, "long": 85.52},
  {"name": "Hotan", "lat": 37.11, "long": 79.91},
  {"name": "Kashgar", "lat": 39.46, "long": 75.99},
  {"name": "Merv", "lat": 37.66, "long": 62.16},
  {"name": "Tehran", "lat": 35.68, "long": 51.38},
  {"name": "Baghdad", "lat": 33.31, "long": 44.36},
  {"name": "Antioch", "lat": 36.19, "long": 36.16},
  {"name": "Athens", "lat": 37.98, "long": 23.72},
  {"name": "Venice", "lat": 45.44, "long": 12.31}
];
  
// create a marker series  
var series_marker = map.marker(data_marker);

Ознакомьтесь с полученной картой коннекторов на основе JS с полным кодом на JSFiddle [или на AnyChart Playground].

C. Настройте маркеры

Маркеры городов можно стилизовать простым способом. Давайте изменим их форму на круги и их цвет на красный. Кроме того, мы отформатируем этикетки, чтобы сделать их более разборчивыми.

// set the marker shape and color  
series_marker
  .type('circle')
  .fill('red')
  .stroke('#000');
  
// format the marker series labels  
series_marker
  .labels()
  .enabled(true)
  .position('center')
  .fontColor('#242424')
  .offsetY(0)
  .offsetX(5)
  .anchor('left-center');

О, и давайте также избавимся от маркеров-стрелок, чтобы они не группировали прогноз. (Не беспокойтесь, таким образом, они все равно будут отображаться при наведении курсора на разъемы.)

// hide arrows in the normal state
series.normal().markers().size(0);
// hide arrows in the hovered state
series.hovered().markers().size(0);
// hide arrows in the selected state
series.selected().markers().size(0);

D. Улучшить всплывающую подсказку

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

Например, мы можем добавить названия городов во всплывающую подсказку серии маркеров.

series_marker.tooltip().format("{%name} is a city located at latitude {%lat}° and longitude {%long}°");

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

Добавьте информацию прямо к данным.

var dataSet = [    
  {points: [33.62, 113.34, 36.05, 103.79], travel: "From Xian to Lanzhou"},
  {points: [36.05, 103.79, 40.14, 94.66], travel: "From Lanzhou to Dunhuang"},
  {points: [40.14, 94.66, 38.14, 85.52], travel: "From Dunhuang to Qiemo"},
  {points: [38.14, 85.52, 37.11, 79.91], travel: "From Qiemo to Hotan"},
  {points: [37.11, 79.91, 39.46, 75.99], travel: "From Hotan to Kashgar"},
  {points: [39.46, 75.99, 37.66, 62.16], travel: "From Kashgar to Merv"},
  {points: [37.66, 62.16, 35.68, 51.38], travel: "From Merv to Tehran"},
  {points: [35.68, 51.38, 33.31, 44.36], travel: "From Tehran to Baghdad"},
  {points: [33.31, 44.36, 36.19, 36.16], travel: "From Baghdad to Antioch"},
  {points: [36.19, 36.16, 37.98, 23.72], travel: "From Antioch to Athens"},
  {points: [37.98, 23.72, 45.44, 12.31], travel: "From Athens to Venice"}
];

Добавьте это в подсказку серии соединителей.

series.tooltip().format('{%travel}');

E. Настройте соединители

Легко изменить цвет обводки коннекторов. Давайте сделаем его коричневым, например

series.stroke('brown');

На самом деле путешествие из Антиохии в Венецию проходило по морю. Почему бы нам не сделать эту часть маршрута другой?

Мы можем изменить настройки отдельных коннекторов в data. Давайте настроим эти два, от Антиохии до Афин и от Афин до Венеции. Сначала делаем их синими. Во-вторых, мы меняем их кривизну. Итак, данные серии разъема будут такими:

var dataSet = [    
  {points: [33.62,113.34, 36.05,103.79], travel: "From Xian to Lanzhou"},
  {points: [36.05,103.79, 40.14, 94.66], travel: "From Lanzhou to Dunhuang"},
  {points: [40.14, 94.66, 38.14, 85.52], travel: "From Dunhuang to Qiemo"},
  {points: [38.14, 85.52, 37.11, 79.91], travel: "From Qiemo to Hotan"},
  {points: [37.11, 79.91, 39.46, 75.99], travel: "From Hotan to Kashgar"},
  {points: [39.46, 75.99, 37.66, 62.16], travel: "From Kashgar to Merv"},
  {points: [37.66, 62.16, 35.68, 51.38], travel: "From Merv to Tehran"},
  {points: [35.68, 51.38, 33.31, 44.36], travel: "From Tehran to Baghdad"},
  {points: [33.31, 44.36, 36.19, 36.16], travel: "From Baghdad to Antioch"},
  {points: [36.19, 36.16, 37.98, 23.72], travel: "From Antioch to Athens", curvature: -0.3, stroke: "blue"},
  {points: [37.98, 23.72, 45.44, 12.31], travel: "From Athens to Venice", curvature: -0.5, stroke: "blue"}
];

F. Добавьте действия масштабирования и управления

Последняя настройка. По умолчанию нашу карту разъемов можно масштабировать с помощью клавиатуры: нажмите Ctrl и + (Cmd и + на Mac) для увеличения или Ctrl и — (Cmd и — на Mac) для уменьшения; используйте клавиши со стрелками для навигации. Но мы можем легко сделать его масштабируемым и другими способами!

Во-первых, мы разрешаем действия масштабирования мышью.

// zoom using the mouse wheel
map.interactivity().zoomOnMouseWheel(true);
// double-click zoom
map.interactivity().zoomOnDoubleClick(true);

Во-вторых, мы добавляем элементы управления пользовательским интерфейсом масштабирования:

  • Для них требуются следующие файлы JS и CSS, на которые мы ссылаемся:
<script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-ui.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.anychart.com/releases/8.11.0/css/anychart-ui.min.css"/>
<link rel="stylesheet" type="text/css" href="https://cdn.anychart.com/releases/8.11.0/fonts/css/anychart-font.min.css"/>
  • Теперь настроим их в JS-коде:
var zoomController = anychart.ui.zoom();
zoomController.target(map);
zoomController.render();

Вот последняя карта соединителей этого руководства!

Эта окончательная интерактивная карта коннекторов JS доступна на JSFiddle [и на AnyChart Playground], где вы можете поэкспериментировать с ней дальше. На всякий случай, полный код также здесь ниже:

<html>
  <head>
    <meta charset="utf-8">
    <title>JavaScript Connector Map</title>
    <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-core.min.js"></script>
    <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-map.min.js"></script>
    <script src="https://cdn.anychart.com/releases/8.11.0/geodata/custom/world/world.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.8.0/proj4.js"></script>
    <script src="https://cdn.anychart.com/releases/8.11.0/js/anychart-ui.min.js"></script>
    <link rel="stylesheet" type="text/css" href="https://cdn.anychart.com/releases/8.11.0/css/anychart-ui.min.css"/>
    <link rel="stylesheet" type="text/css" href="https://cdn.anychart.com/releases/8.11.0/fonts/css/anychart-font.min.css"/>
    <style type="text/css">      
      html, body, #container { 
        width: 100%; 
        height: 100%; 
        margin: 0; 
        padding: 0; 
      } 
    </style>
  </head>
  <body>
    <div id="container"></div>
    <script>
anychart.onDocumentReady(function () {
  // create a data set for connectors
  var dataSet = [    
    {points: [33.62, 113.34, 36.05, 103.79], travel: "From Xian to Lanzhou"},
    {points: [36.05, 103.79, 40.14, 94.66], travel: "From Lanzhou to Dunhuang"},
    {points: [40.14, 94.66, 38.14, 85.52], travel: "From Dunhuang to Qiemo"},
    {points: [38.14, 85.52, 37.11, 79.91], travel: "From Qiemo to Hotan"},
    {points: [37.11, 79.91, 39.46, 75.99], travel: "From Hotan to Kashgar"},
    {points: [39.46, 75.99, 37.66, 62.16], travel: "From Kashgar to Merv"},
    {points: [37.66, 62.16, 35.68, 51.38], travel: "From Merv to Tehran"},
    {points: [35.68, 51.38, 33.31, 44.36], travel: "From Tehran to Baghdad"},
    {points: [33.31, 44.36, 36.19, 36.16], travel: "From Baghdad to Antioch"},
    {points: [36.19, 36.16, 37.98, 23.72], travel: "From Antioch to Athens", curvature: -0.3, stroke: "blue"},
    {points: [37.98, 23.72, 45.44, 12.31], travel: "From Athens to Venice", curvature: -0.5, stroke: "blue"}
  ];
  // create a map
  var map = anychart.map();
  // create a connector series
  var series = map.connector(dataSet);
  
  // set geodata
  map.geoData(anychart.maps['world']);
  // title the map
  map.title("Silk Road Trade Route from Xian to Venice");
  
  // create a data set for markers
  var data_marker = [
    {"name": "Xian", "lat": 33.62, "long": 113.34},
    {"name": "Lanzhou", "lat": 36.05, "long": 103.79},
    {"name": "Dunhuang", "lat": 40.14, "long": 94.66},
    {"name": "Qiemo", "lat": 38.14, "long": 85.52},
    {"name": "Hotan", "lat": 37.11, "long": 79.91},
    {"name": "Kashgar", "lat": 39.46, "long": 75.99},
    {"name": "Merv", "lat": 37.66, "long": 62.16},
    {"name": "Tehran", "lat": 35.68, "long": 51.38},
    {"name": "Baghdad", "lat": 33.31, "long": 44.36},
    {"name": "Antioch", "lat": 36.19, "long": 36.16},
    {"name": "Athens", "lat": 37.98, "long": 23.72},
    {"name": "Venice", "lat": 45.44, "long": 12.31}
  ];
  
  // create a marker series  
  var series_marker = map.marker(data_marker);
  
  // define the scale
  var mapScale = map.scale();
  mapScale.minimumX(30);
  mapScale.maximumX(70);
  mapScale.minimumY(0);
  mapScale.maximumY(80);
  
  // set the marker shape and color  
  series_marker
    .type('circle')
    .fill('red')
    .stroke('#000');
  
  // format the marker series labels  
  series_marker
    .labels()
    .enabled(true)
    .position('center')
    .fontColor('#242424')
    .offsetY(0)
    .offsetX(5)
    .anchor('left-center');
  
  // customize the tooltip
  // for the connector series
  series.tooltip().format('{%travel}');
  // for the marker series
  series_marker.tooltip().format("{%name} is a city located at latitude {%lat}° and longitude {%long}°");
  
  // hide the connector marker (arrows) in all states
  series.normal().markers().size(0);
  series.hovered().markers().size(0);
  series.selected().markers().size(0);
  // change the connector series color
  series.stroke('brown');
  
  // enable zoom actions
  map.interactivity().zoomOnMouseWheel(true);
  map.interactivity().zoomOnDoubleClick(true);
  
  // add zoom controls
  var zoomController = anychart.ui.zoom();
  zoomController.target(map);
  zoomController.render();
  // set the container id
  map.container('container');
  // draw the map
  map.draw();
});
    </script>
  </body>
</html>

Заключение

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

Публикуется с разрешения Авана Шресты. Первоначально появилось на Codementor под заголовком Как создать карту коннекторов в JavaScript 14 июля 2022 г.

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

Дополнительные руководства по построению диаграмм JavaScript можно найти в нашем блоге.

Первоначально опубликовано на https://www.anychart.com 15 июля 2022 г.

Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter и LinkedIn. Посетите наш Community Discord и присоединитесь к нашему Коллективу талантов.