Мы выпустили редактор стилей. Подробно о том, как с ним можно настроить карту под задачи сервиса, можно почитать на vc.ru. На Хабре же хотим рассказать о концепции StyleZoom, которую мы используем в том числе и в редакторе стилей.
Под катом — небольшой рассказ о зум-левелах: почему в стандартном виде они не подходят для больших территорий и как масштаб влияет на загрузку тайлов и внешний вид карты.
Для обозначения масштаба в WebGL-карте 2ГИС, как и во многих других картах, используется число — зум-левел или просто зум. Зум, равный нулю, соответствует масштабу карты, при котором весь мир помещается в квадрат размером 256?256 px.
Карта мира при zoom = 0
Увеличение зума на единицу соответствует растяжению карты в два раза. На первом зуме весь мир будет размером 256 ? 2 = 512 px. На четвёртом получаем размер 256 ? 2 ? 2 ? 2 ? 2 = 4096 px.
Такая система позволяет обозначать диапазон масштабов удобными для понимания числами. Например, zoom = 11 — примерно один крупный город на экране, zoom = 19 позволяет детально рассмотреть здания и проходы между ними.
В картах 2ГИС используется картографическая проекция Меркатора. Картографическая проекция — способ отобразить сферическую поверхность Земли на плоской карте.
Так как плоскость и шар — не одно и то же, любая картографическая проекция искажает форму или размеры объектов. В проекции Меркатора объекты на больших широтах на карте выглядят больше, чем объекты на экваторе. Поэтому на таких картах Гренландия выглядит размером с Африку, хотя фактически её площадь меньше площади Африки в 14 раз. Здесь можно рассмотреть, как проекция искажает размеры стран.
Если Россию приблизить к экватору, её размер на карте значительно уменьшается
Растяжение объектов пропорционально 1 / cos(lat), где lat — широта объекта. Из этой формулы следует, что объекты на широте Санкт-Петербурга (lat = 60°) на карте будут растянуты в два раза. А объекты на Северном или Южном полюсах (lat = 90°) и вовсе растянутся до бесконечности. Именно поэтому на картах в проекции Меркатора никогда не рисуются полюса — на них обрезается всё севернее и южнее ?85° широты.
Подробнее о проекции Меркатора можно почитать в этом наглядном и увлекательном материале.
Из свойств проекции Меркатора вытекает главная проблема с зумами: один и тот же зум-левел на разных широтах соответствует разным фактическим масштабам карты.
Сравним скриншоты карты на 14-м зуме в Мурманске (широта 69°) и Ташкенте (широта 41°).
15-й зум в Мурманске
15-й зум в Ташкенте
Видно, насколько сильно отличаются по размеру дома. В Мурманске они крупные, в Ташкенте же карта мельчит.
При создании стилей карты мы хотим придать ей определённый внешний вид. Для этого задаём ширину дорог в пикселях в зависимости от зума или зум, с которого начинаем показывать дома. Стили, написанные для одной широты, на другой будут выглядеть совсем иначе. Смысл, заложенный в них, исказится, так как зумы будут означать уже другой фактический масштаб.
Для решения этой проблемы мы ввели понятие styleZoom, который может отличаться от обычного zoom.
styleZoom вычисляется из zoom и широты по сдедующей формуле: styleZoom = zoom + log2(1 / (2 * cos(lat)).
Из формулы вытекают следующие свойства styleZoom:
Посмотрим теперь, как будут выглядеть Ташкент и Мурманск при styleZoom = 15.
Ташкент, styleZoom = 15 (zoom ? 15.59)
Мурманск, styleZoom = 15 (zoom ? 14.53)
Хорошо видно, что styleZoom соответствует реальному масштабу карты вне зависимости от широты: дома визуально не отличаются по размеру, карта в двух разных городах выглядит одинаково.
У механизма коррекции есть недостатки, которые проявляются в двух сценариях работы с картой.
zoom < 9
На небольших зумах, когда на экране виден весь мир или его бoльшая часть, перетаскивание карты вверх-вниз приводит к большим изменениям широты и, соответственно, styleZoom.
Во время перетаскивания это может привести к загрузке новых тайлов, переключению стилей, появлению или исчезновению объектов и т.п. Чтобы избежать этого эффекта, при zoom < 9 коррекция отключается, и styleZoom приравнивается к zoom.
lat > 60°
На очень больших широтах styleZoom становится сильно больше zoom. Так как styleZoom отвечает за то, какие тайлы грузить, может оказаться, например, что на 14-м зуме мы загрузим и отобразим тайлы 16-го зума. Тайл 16-го зума в 16 раз меньше по площади, чем тайл 14-го зума. И если обычно на экран попадает ?30 тайлов, то в этом случае их будет 480. А количество тайлов сильно влияет на производительность. Чтобы не загружать видеокарту на этих широтах, при lat > 60° коррекция отключается, и styleZoom также приравнивается к zoom.
Подключайте API наших WebGL-карт и оформляйте карты под задачи вашего сервиса, не переживая, как они будут выглядеть в разных городах.
За пост отдельное спасибо Лёше Федосову. Лёха, привет!
Под катом — небольшой рассказ о зум-левелах: почему в стандартном виде они не подходят для больших территорий и как масштаб влияет на загрузку тайлов и внешний вид карты.
Зум-левел
Для обозначения масштаба в WebGL-карте 2ГИС, как и во многих других картах, используется число — зум-левел или просто зум. Зум, равный нулю, соответствует масштабу карты, при котором весь мир помещается в квадрат размером 256?256 px.
Карта мира при zoom = 0
Увеличение зума на единицу соответствует растяжению карты в два раза. На первом зуме весь мир будет размером 256 ? 2 = 512 px. На четвёртом получаем размер 256 ? 2 ? 2 ? 2 ? 2 = 4096 px.
Такая система позволяет обозначать диапазон масштабов удобными для понимания числами. Например, zoom = 11 — примерно один крупный город на экране, zoom = 19 позволяет детально рассмотреть здания и проходы между ними.
Проекция Меркатора
В картах 2ГИС используется картографическая проекция Меркатора. Картографическая проекция — способ отобразить сферическую поверхность Земли на плоской карте.
Так как плоскость и шар — не одно и то же, любая картографическая проекция искажает форму или размеры объектов. В проекции Меркатора объекты на больших широтах на карте выглядят больше, чем объекты на экваторе. Поэтому на таких картах Гренландия выглядит размером с Африку, хотя фактически её площадь меньше площади Африки в 14 раз. Здесь можно рассмотреть, как проекция искажает размеры стран.
Если Россию приблизить к экватору, её размер на карте значительно уменьшается
Растяжение объектов пропорционально 1 / cos(lat), где lat — широта объекта. Из этой формулы следует, что объекты на широте Санкт-Петербурга (lat = 60°) на карте будут растянуты в два раза. А объекты на Северном или Южном полюсах (lat = 90°) и вовсе растянутся до бесконечности. Именно поэтому на картах в проекции Меркатора никогда не рисуются полюса — на них обрезается всё севернее и южнее ?85° широты.
Подробнее о проекции Меркатора можно почитать в этом наглядном и увлекательном материале.
Проблемы с зумом и проекцией Меркатора
Из свойств проекции Меркатора вытекает главная проблема с зумами: один и тот же зум-левел на разных широтах соответствует разным фактическим масштабам карты.
Сравним скриншоты карты на 14-м зуме в Мурманске (широта 69°) и Ташкенте (широта 41°).
15-й зум в Мурманске
15-й зум в Ташкенте
Видно, насколько сильно отличаются по размеру дома. В Мурманске они крупные, в Ташкенте же карта мельчит.
При создании стилей карты мы хотим придать ей определённый внешний вид. Для этого задаём ширину дорог в пикселях в зависимости от зума или зум, с которого начинаем показывать дома. Стили, написанные для одной широты, на другой будут выглядеть совсем иначе. Смысл, заложенный в них, исказится, так как зумы будут означать уже другой фактический масштаб.
Решение
Для решения этой проблемы мы ввели понятие styleZoom, который может отличаться от обычного zoom.
Обычный zoom | StyleZoom |
Определяет масштабирование объектов | Определяет, какие тайлы грузить |
Записывается в url | Определяет, для какого масштаба применять стили |
Используется в привычных методах getZoom / setZoom | Используется в методах getStyleZoom / setStyleZoom |
Совпадает с растровыми тайлами |
styleZoom вычисляется из zoom и широты по сдедующей формуле: styleZoom = zoom + log2(1 / (2 * cos(lat)).
Из формулы вытекают следующие свойства styleZoom:
- На широте 60° styleZoom = zoom. Так как стили изначально писались на Новосибирск и Москву, решили взять эту широту за базовую.
- На широтах <60° styleZoom < zoom. На экваторе styleZoom = zoom — 1.
- На широтах >60° styleZoom > zoom.
Посмотрим теперь, как будут выглядеть Ташкент и Мурманск при styleZoom = 15.
Ташкент, styleZoom = 15 (zoom ? 15.59)
Мурманск, styleZoom = 15 (zoom ? 14.53)
Хорошо видно, что styleZoom соответствует реальному масштабу карты вне зависимости от широты: дома визуально не отличаются по размеру, карта в двух разных городах выглядит одинаково.
Ограничения
У механизма коррекции есть недостатки, которые проявляются в двух сценариях работы с картой.
zoom < 9
На небольших зумах, когда на экране виден весь мир или его бoльшая часть, перетаскивание карты вверх-вниз приводит к большим изменениям широты и, соответственно, styleZoom.
Во время перетаскивания это может привести к загрузке новых тайлов, переключению стилей, появлению или исчезновению объектов и т.п. Чтобы избежать этого эффекта, при zoom < 9 коррекция отключается, и styleZoom приравнивается к zoom.
lat > 60°
На очень больших широтах styleZoom становится сильно больше zoom. Так как styleZoom отвечает за то, какие тайлы грузить, может оказаться, например, что на 14-м зуме мы загрузим и отобразим тайлы 16-го зума. Тайл 16-го зума в 16 раз меньше по площади, чем тайл 14-го зума. И если обычно на экран попадает ?30 тайлов, то в этом случае их будет 480. А количество тайлов сильно влияет на производительность. Чтобы не загружать видеокарту на этих широтах, при lat > 60° коррекция отключается, и styleZoom также приравнивается к zoom.
Вместо вывода
Подключайте API наших WebGL-карт и оформляйте карты под задачи вашего сервиса, не переживая, как они будут выглядеть в разных городах.
За пост отдельное спасибо Лёше Федосову. Лёха, привет!
Enmar
Интересно.
Захотелось даже проверить есть ли у Яндекс Карт такая адаптация.
atri1
у гугл и яндекс карт была поддержка WebGL но ее убрали в пользу CSS
WebGL слишком нестабильный и непредсказуемый в браузерах(течет падает тормозит лагает), и это никогда и никак не исправить
Enmar
Я думаю, что такое "умное" масштабирование можно реализовать и без WebGL.
могу ошибаться, никогда не смотрел как оно все внутри устроено.
Trufi
По-моему, такая ситуация была 10 лет назад :) Технологии, браузеры и компьютеры пользователей постоянно улучшаются. И большинство крупных картографических проектов в вебе уже сейчас так или иначе используют WebGL (2GIS, Google, Here, MapBox, Yandex).
atri1
WebGL не получает обновлений и ломается все сильнее в браузерах, Apple скоро от него тоже откажется.
WebGL2 год назад объявлен deprecated и будет удален из всех браузеров в будущем(уже удален из всех браузеров для Apple девайсов)
WebGPU "якобы" заменя WebGL, на данный момент WebGPU еще в альфе и не известно будет ли Apple поддерживать его.
в 2020 году есть только CSS как стабильная технология которая работает везде
из WebGPU можно сломать любую ОС(крашить видеодрайвер) всеголиш сделав пару ошибок в хело-ворд, если поддержка доступа к GPU в браузерах и будет, то будет как Flash-plugin с запросом "разрешения" на использование GPU этим сайтом, и запретом по умолчанию… (очевидно что 99.9% юзеров будут нажимать на нет всегда и популярность такой технологии будет нулевая(разве что Гугл пропишет свои сайты в исключения дав им эксклюзивную возможность использовать GPU без разрешений))
Trufi
Не забудьте еще про стабильную технологию HTML :)
Всё таки Applе пометили deprecated только OpenGL. Речи про WebGL не идет, и это в тот же момент подтвердил их лид разработки Dean Jackson. Разработка WebGL 2 идет, недавно он был включен по умолчанию в Safari Technology Preview.
Говорить о том, как будет в итоге работать WebGPU, кажется, еще рано, технология не готова.
Woodroof
Что такое отрисовка карт на CSS? Карты совершенно точно никто в HTML не верстает.
Возможно, вы спутали с MapCSS/CartoCSS, но это всего лишь названия спецификаций стилей карты, и к стандарту CSS они имеют отношение только тем, что синтаксически на него похожи. Да и MapBox уже отказался от своей CSS-подобной спецификации в пользу более новой. А рендерит MapBox тоже при помощи всё того же WebGL.
И растровых карт уже тоже не осталось ни у Гугла, ни у Яндекса. Точнее, остались, но только для обратной совместимости.
atri1
-webkit-transform
благодаря которому можно кубемап(панораму) рендерить и подсвечивать нужные детали… как и сделано в гуглкартах(там нет WebGL)Woodroof
Тайлы-то векторные, а не растровые. А это всё сильно меняет :)
У вас тогда остаётся только вариант напрямую рисовать на canvas. И CSS тут никак не поможет.
Открываю карты Google. В DOM вижу canvas. В инструментах разработчика в Performance есть строчка с GPU. Может, у вас, в вашем браузере и в вашей системе WebGL на их картах отключен, но у меня — нет.