http://ivanpoukhkal.ru/interactive/flights/

Cделано с помощью js-библиотеки , предназначенной для создания интерактивных векторных карт на основе SVG. Её основная «фишка» — в поддержке различных картографических проекций.

Данные

Чтобы не тратить много времени на подготовку геопривязанных данных, я решил ещё раз обратиться к авиационной тематике. Я знал, что на openflights.org ведётся аэропортов с их географическими координатами, так что оставалось подобрать что-нибудь связанное с перелётами между ними. В августе как раз свернула работу авиакомпания Wind Jet и я решил нарисовать европейские маршруты «схлопнувшихся» в этом году перевозчиков пассажиров.

Первоначально я думал собрать данные по двум-трём авиакомпаниям вручную, но на том же openflights оказалась база маршрутов по состоянию на январь 2012 года, так что препятствий к рисованию всех линий не было. Количество самолётов к моменту прекращения деятельности я взял из Википедии. Ещё по Википедии я уточнил названия некоторых аэропортов (например, чешский аэропорт «Брно—Туржаны», который в базе назывался просто «Туржаны»). Там, где возможно, я уточнил действовавшие расписания авиакомпаний по и .

Все три таблицы (аэропорты, маршруты и авиакомпании) были сохранены в CSV (50 КБ в сумме).

Внутреннее устройство библиотеки

«Картограф» отвечает за географическую часть работы: преобразование координат из широты и долготы в абсциссу и ординату рисунка в соответствии с выбранной проекцией, а также умеет наносить данные по нескольким типовых решениям: с кругами или иконками в заданных точках, либо с кодированием цветом регионов в зависимости от данных (то, что по-русски называют картограммой, а по-английски — choropleth map).

Непосредственно для рисования SVG в браузере для работы требуется подключить — в результате все элементы карты являются объектами «Рафаэля» и интерактивность обеспечивается именно возможностями этой библиотеки.

Также использованы:

  • ;
  • — для расчёта , кратчайших линий между точками земного шара;
  • — для чтения данных из CSV-таблиц;
  • — библиотека для работы с коллекциями в функциональном стиле.

Общий размер скриптов: 277 КБ (библиотеки в минифицированном виде) + 11 КБ (относящийся к созданию конкретно этой карты).

Начало работы

«Картограф» на входе понимает SVG-файл с географическими метаданными: в какой проекции карта и каковы 2 широты и 2 долготы, ограничивающие рисунок по краям. Есть два пути получения такого файла: (а) взять обычную SVG-карту, узнать проекцию и проставить ограничения в файл вручную, (б) воспользоваться написанном на Питоне , который сделает из с геоданными SVG-карту с уже прописанной метаинформацией. При работе с ним также можно указать желаемую проекцию на выходе или какие объекты включать в итоговую карту.

Я выбрал путь (б) — в конце концов, библиотеку-то мы выбрали именно из-за большого количества проекций. Найти шейп-файл для обзорной карты Европы — дело несложное, достаточно просто взять , где уже прописаны коды стран и регионов (впрочем, на моей карте со странами манипуляций нет, так что коды тут не понадобятся).

Предлагается , которая на Маке работает ровно до того момента, когда ей требуются установленные Command Line Tools. Точнее, эта причина устанавливается позже, сообщение выдаётся немного другое: «AAA не нашло BBB». В итоге CLT были приняты благосклонно и установка завершилась успешно.

Преобразование управляется (в yaml или json-формате). Вот, например, мой для «спутниковой» проекции (вид со спутника, висящего над определённой точкой земной поверхности):

proj:
        id: «satellite»
        «lon0»: 13.5
        «lat0»: 50
        «dist»: 1.52
layers:
— id: «countries»
  src: shp/ne_50m_admin_0_countries.shp # шейп-файл
  simplify: false # не упрощать SVG-пути
  attributes: # переносить коды стран в карту
          «ISO_A3»: «iso»
          «NAME»: «name»
  filter: [«ISO_A3», «in not», [«DZA», «SYR», «TUN»]] # исключить Алжир, Сирию и Тунис
  styles: # стили для объектов этого слоя
          fill: «#000»
          stroke: «#ccc»
          stroke-opacity: 0.5
bounds: # границы, примерно соответствующие Европе
   mode: bbox
   data: [-11,36,38,68] # порядок: долгота левая, правая; широта нижняя, верхняя
export: # размер на выходе и число знаков после запятой
        width: 800
        round: 2

Для выбора проекции Георг предлагает использовать и для границ отреза.

Всё это прекрасно, но увы, преобразование — то, за чем мы вообще пришли — работает не для всех проекций. Либо что-то не доделано, либо какие-то проблемы с зависимостями, но большая часть из них просто «ImportError: cannot import name MultiPolygon» или какую-нибудь другую.

Из работающих можно, например, посмотреть на проекцию :

SVG-карта в (но размер от выбора проекции зависит мало) в итоге заняла 190 КБ.

Приступаем к картографингу

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

Отрисовка карты основывается на слоях. Сначала загружается SVG-карта, а затем на неё накладываются слои регионов в цветовом кодировании или символов одного из типов: круги, текстовые метки или иконки (из графических файлов). При создании слоя ему передается массив необходимых данных и функции, генерирующие местоположение и связанные с объектом данные.

На моей карте создано два слоя: оранжевые круги аэропортов и текстовые метки с их названиями (а именно: городами, если крупный аэропорт один, или городами с аэропортами в скобках, если их несколько). Линии перелётов я рисую в отдельным проходе по базе маршрутов функцией .

Про возможность штатной передачи идентификатора через параметр я не знал и приспособил для этого атрибут title, куда записывался код аэропорта по классификации IATA (LED, SVO, HEL…). Но заботливый «Картограф» при генерации страницы оборачивает элемент «circle» в «a», чтобы показывать всплывающую подсказку. Поэтому после окончания формирования карты этот элемент приходится снова убирать.

Гистограмма

Гистограмма рисуется примитивами «Рафаэля» прямо на карте. Здесь создаются линии сетки и прямоугольники, которым придаются обработчики событий.