Привет, Хабр.


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


Quick Dive


С точки зрения большинства современных картографических решений можно выделить несколько базовых подходов к отрисовке карты:


  • растровый (статичные файлы — картинки с тайлами, хранящиеся на CDN и имеющие свой TTL)
  • векторный

Тут нужно сделать ремарку, тайл, для тех кто не вкурсе, это специальная блочная координатная сетка (параллельно тайлами называются и статичные изображения), которая характеризуется тремя координатами (z — зум, x, y), на каждом уровне количество тайлов $2^{(2 \times zoom)}$


Наиболее интересным на сегодняшний день является векторный формат.


Почему? Собственно, нужно начать с проблем, связанных с растровым форматом:


  • Дискретные уровни зума (от 0 до 20 в большинстве случаев)
  • Жёсткая привязка стилистики и данных на тайловых слоях
  • Классические недостатки растра

Какие перспективы предлагает векторный формат? Собственно, их несколько:


  • Зум не связан чётко с тайлами на определённом слое, а может меняться с любой точностью и плавностью
  • Поскольку зачастую именно клиент (не рассматривая вариант промежуточного рендера) рендерит карту, то именно он определяет какие данные и в каком стиле он хочет отрисовывать
  • Отличное качество в независимости от разрешения и т.д., что в общем-то классическое преимущество вектора над растром

Собственно всё с векторным форматом хорошо, но есть и свои недостатки. Как минимум, векторный формат сложнее кэшировать, это не так очевидно, как в большинстве случаев с растровым форматом, где достаточно предгенерированные тайлы сложить на CDN, настроить TTL и перегенерацию и больше не думать об этом.


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


Решение


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


  1. Загрузка целиком GeoJSON и рендер его (большинство отваливаются на этом варианте :)). Собственно преимущество, в том что практически все популярные библиотеки Google Карты, Yandex Карты, Mapbox, Leaflet и т.д., его так или иначе поддерживают. Однако, далеко не все делают это эффективно, например, по запросу в гугл по поводу эффективного решения для загрузки большого числа точек в Mapbox первой ссылкой будет их решение — supercluster, который по факту является серверной утилитой, которая загружает, подготавливает GeoJSON данные и возвращает их клиенту.


  2. Загрузка только находящегося в viewport. Идея довольно простая, мы загружаем только то что находится в viewport (* в некоторых случаях лениво подгружаются и близлежащие тайлы). Реализация такого есть в коробке например в Yandex Картах — LoadingObjectManager, в том числе он может делать и кластеризацию на клиенте. У них есть и RemoteObjectManager, который уже ожидает кластеризованные данные от сервера.


  3. Предгенерация статичных тайлов и загрузка их. Тоже имеет место быть, особенно в случае с высоконагруженными сервисами, но не особо интересно. Чаще всего генерируются тайлы с помощью инструмента, как например Mapnik и заливаются на CDN, либо используется сторонняя утилита/библиотека, которая делает всю эту работу самостоятельно.


  4. Mapbox Vector Tiles, собственно один из векторных форматов для карт, который описывает различные геометрии, их стилистику и т.д… Идея при использовании такого метода заключается в формировании своего MVT эндпоинта, который собственно может:
    • Возвращать геометрии
    • Кластеризовать точки
    • Упрощать геометрии на малых уровнях зума
    • Другое

Данный формат отлично поддерживается решениями от Mapbox, так же есть библиотеки для Leaflet.


С точки зрения хранилища для ГИС данных, которое бы к тому же давало возможность эффективно проводить операции над ними можно выбрать PostGIS, который к слову даёт все необходимые операции для описанного выше, в том числе и генерацию MVT (Mapbox Vector Tiles):


  • Включение геометрии в тайл (прямоугольник) с помощью оператора @
  • Генерация MVT — ST_AsMVT, ST_AsMVTGeom

Спасибо за внимание, надеюсь на конструктивный фидбэк, если будет интересно могу рассказать ещё о некоторых моментах работы с картами!


Примеры описанного выше доступно в моём GitHub

Комментарии (3)


  1. Melorian
    30.03.2018 10:04

    Так какой способ-то? :D


    1. GetJump Автор
      30.03.2018 21:05

      Зависит от потребностей, но в целом это 2 или 4 — ый. Я сам сейчас в разрабатываемом проекте остановился на втором, поскольку там уже были Яндекс Карты, в целом я сторонник векторного решения, как более состоятельного, но нужно потратить немного больше сил на бэкэнд, в идеале вообще была бы около микросервисная архитектура и использование готового решение на JS (да, на нём действительно очень много всего).

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


  1. za90
    01.04.2018 11:21

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