javascript

Leaflet 1.x.x vs Openlayers 4.x.x. Часть 2. Как рисуются карты

  • вторник, 10 октября 2017 г. в 03:13:29
https://habrahabr.ru/post/334676/
  • Геоинформационные сервисы
  • Open source
  • JavaScript


В прошлой статье обещал, что эта будет про сообщества и плагины, но потом решил, что правильней будет сначала рассказать о том, как в данных фреймворках рисуются карты. Начну с Openlayers, потом Leaflet, потом его плагины.

image

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

Как рисует openlayers


Openlayers использует два варианта рисования — Canvas и WebGL ( DOM рендер для тайлов и изображений был удален из современной 3-й версии). Компонент map создает div, в котором и трудятся два этих рендера. Сильно упрощенная последовательность вызовов примерно такая:

  1. В компоненте карты вызывается функция renderFrame
  2. Определяются слои, которые видимы на данном масштабе
  3. Каждый из видимых слоев рисует своим рендером изображение. Помимо разделения на по типам драйверов (canvas и webgl), далее рендеры делятся еще и по типам слоев (ol.renderer.canvas.TileLayer, ol.renderer.canvas.VectorLayer и тд).
  4. К полученным изображениям слоев добавляется прозрачность, трансформации и вырезание ( clip, если есть) и они все рисуются в общем контексте карты.

Оба рендера работают неплохо, однако, если переключитесь на webgl, то стоит помнить, что ресурсы (например картинки тайлов) нужно будет пускать через прокси, иначе получите:
Uncaught DOMException: Failed to execute 'texImage2D' on 'WebGLRenderingContext': The cross-origin image at may not be loaded.

Если сервер поддерживает cross-origin, а ошибку все равно выдает поставьте в настройках источника изображения crossOrigin: 'anonymous'

Как рисует Leaflet


Для начала, вот хорошая схема классов, которая отображается опять же через leaflet.
Leaflet для рисования карт создает несколько панелей (Pane), которые являются DOM элементами (div), с которыми уже работают слои.
Название Описание zIndex
mapPane основная панель содержит в себе все остальные auto
tilePane панель для тайловых слоев 200
overlayPane панель для векторный слоев 400
shadowPane панель для теней 500
markerPane панель для маркеров 600
tooltipPane панель для подсказок 650
popupPane панель для появляющихся данных по объектам 700

И тут кроется первая интересная деталь, если в Openlayers нумерация по zIndex сквозная для всех слоев по умолчанию, то в Leaflet, слои получаются сгруппированными. Если вы вдруг хотите, чтобы ваш тайловый слой когда-нибудь был «над» векторным, вам надо или принудительно указывать у конкретного тайлового слоя в options pane: overlay, или если сквозная нумерация нужна у всех слоев, то складывать их все в один. Кстати, можно создавать свой pane и необязательно он должен быть внутри mapPane.

А дальше начинается самое интересное, если в Openlayers для всех слоев, используется одинаковый набор рендеров, то Leaflet, каждый из слоев сам выбирает как и чем ему рисоваться. Например тайловые слои и ImageOverlay рисуются только DOM-элементами (хотя в плагинах есть вариации на тему рисования тайлов с использованием WebGl и Canvas). Для векторных слоев слоев используется SVG или Canvas, если оба поддерживаются браузером, по умолчанию используется SVG.

Особенности рисования в разных плагинах Leaflet


Как я уже сказал, несмотря на то, что из коробки у Leaflet нет webgl рендера, некоторые плагины используют эту технологию. Leaflet.TileLayer.GL, например, создает вместо изображения тайла canvas, в который рисует рендер Webgl. С помощью данного плагина можно с GPUшной производительностью поиграть с пикселями в тайлах. Вот пример раскраски пикселей в тайлах по широте:



Или вот от того же автора Leaflet.GLMarkers позволяет рисовать большие объемы точек на карте (маркеры могут быть анимированы), хотя выглядит кривовато, особенно нерабочая анимация зумирования напрягает.



Бывают тяжелые случаи и у плагинов, которые обслуживаются серьезными компаниями. Например, esri-leaflet в DynamicMapLayer при каждом рефреше создает новый слой ImageOverlay, причем создает его когда загрузилась соответствующая картинка, т.е. порядок слоев на карте постоянно перемешивается, работать с z-index невозможно. Вашему покорному слуге даже пришлось делать улучшенный вариант данного слоя, также там есть переход через 180 меридиан, которого нет в оригинальном плагине.

Еще одна частая проблема: разная поддержка плагинами 2х основных версий leaflet — 0.7 и 1.0. Между ними очень много критических изменений, и плагины могут не работать в конкретной версии. Бывает еще так: один плагин работает только в версии 1.0, а другой нужный нам плагин автор еще не обновил или совсем забил на его обслуживание ( хотя сейчас таких все меньше) и он работает только под старой.

Короче говоря, основная проблема рисования leaflet, то что каждый плагин делает все как ему заблагорассудится, кто-то создает html img, кто-то рисует в canvas, кто-то webgl'ом рисует в canvas в тайл и тд. И дальнейшая работа с этим в комплексе становится проблематичной.

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