В веб-картографии координаты существуют одновременно в нескольких пространствах, каждое из которых решает свою задачу: хранение географического положения, математическая проекция на плоскость и отображение на экране. Внутри MapLibre GL JS вся цепочка преобразований строится вокруг строгого разделения этих уровней.
Первичный уровень — географические координаты:
Они задаются в системе WGS84, которая соответствует стандарту EPSG:4326. В этой системе поверхность Земли описывается эллипсоидом, а координаты выражаются в градусах.
Однако экранное отображение требует плоской модели, что приводит к использованию картографических проекций.
EPSG:4326 — это сферическая модель координат, где:
Внутри MapLibre GL JS эти значения представлены объектом
LngLat, который инкапсулирует пару:
{lng: number, lat: number}
Особенность системы: она не пригодна для прямого отображения на плоскости без искажений, так как не содержит проекционного преобразования.
Основная рабочая проекция в веб-картах — Web Mercator (EPSG:3857), используемая для тайловой системы и рендеринга.
Её ключевая особенность — преобразование сферических координат в псевдоплоские:
Формулы преобразования:
x = R * λ
y = R * ln(tan(π/4 + φ/2))
где:
Искажения возрастают к полюсам, поэтому карта обрезается примерно на ±85.0511°.
Внутри рендерера MapLibre GL JS используется промежуточное пространство — world coordinates.
Это нормализованная плоскость, где:
Переход выглядит так:
LngLat → Web Mercator → World Coordinates → Screen Coordinates
Ключевой механизм трансформации — экспоненциальное масштабирование при изменении zoom.
Фундаментальная зависимость:
scale = 2^zoom
Это означает:
Таким образом, координаты в world space масштабируются относительно центра карты.
Карты разбиваются на квадратные тайлы размером 256×256 пикселей.
На уровне zoom z:
tiles_per_axis = 2^z
Каждый тайл имеет координаты:
(x_tile, y_tile)
где:
Переход от Web Mercator к тайлам:
x_tile = (x_world * scale) / tileSize
y_tile = (y_world * scale) / tileSize
Эта система обеспечивает:
В API MapLibre GL JS ключевые методы:
map.project(lngLat)map.unproject(point)Алгоритм включает три шага:
Результат:
Point = { x: pixelX, y: pixelY }
unproject выполняет обратную цепочку:
Формула обратной проекции широты:
φ = 2 * atan(e^y / R) - π/2
Внутренний рендер использует матричную модель:
M = P × V × W
где:
Каждая точка проходит через цепочку:
LngLat → world matrix → view transform → screen
Долгота имеет циклическую природу:
-180° ≡ 180°
Поэтому MapLibre GL JS поддерживает “wrap”:
Математически это реализуется через модуль:
x_wrapped = x mod worldWidth
Из-за особенностей Web Mercator:
lat ∈ [-85.0511°, 85.0511°]
Это предотвращает бесконечный рост y-координаты в проекции.
Экранное пространство зависит от:
Внутренний pipeline переводит координаты в device pixels:
devicePixel = cssPixel × devicePixelRatio
Это обеспечивает корректную отрисовку на Retina-дисплеях.
При rotation вводится дополнительное преобразование:
x' = x cos θ - y sin θ
y' = x sin θ + y cos θ
Это влияет на:
Все GeoJSON-объекты проходят ту же цепочку преобразований:
Каждая вершина трансформируется независимо, после чего применяется triangulation на уровне world space.
Полный pipeline координат:
GeoJSON (LngLat)
↓
WGS84 (EPSG:4326)
↓
Web Mercator (EPSG:3857)
↓
World coordinates
↓
Camera transform (zoom / pan / rotate)
↓
Screen coordinates
Каждый этап строго детерминирован и обратим (за исключением клиппинга и ограничений Mercator-проекции), что обеспечивает согласованность геометрии, тайлов и интерактивных операций в MapLibre GL JS.