Преобразование координат

В системе Google Maps JavaScript API координаты не ограничиваются привычной парой широта/долгота. Для корректного отображения карты используется несколько уровней представления: географические координаты, мировая система координат (world coordinates), пиксельная система (pixel coordinates) и тайловая разметка (tile coordinates). Преобразование между этими системами является базовой операцией при работе с кастомными слоями, оверлеями и интерактивными элементами.

Географическая система координат опирается на эллипсоид WGS84, где точка задаётся значениями широты и долготы:

  • широта (latitude) — угол относительно экватора
  • долгота (longitude) — угол относительно нулевого меридиана

Однако для отрисовки карты напрямую эти значения не используются. Они проходят несколько этапов преобразования.


Проекционная модель Mercator

Карты в Google Maps JavaScript API используют проекцию Web Mercator. Она переводит сферические координаты в плоскую систему, удобную для рендеринга на экране.

Преобразование широты в координату Y выполняется через логарифмическую функцию:

  • крайние широты ограничиваются значением около ±85.0511°
  • долгота линейно отображается по оси X

Математически:

  • X пропорционален долготе
  • Y = ln(tan(π/4 + φ/2))

где φ — широта в радианах.

Эта модель обеспечивает:

  • равномерное масштабирование по долготе
  • сохранение углов (конформность)
  • удобное разбиение на тайлы

Мировые координаты (World Coordinates)

Мировые координаты — это промежуточный слой между географическими координатами и пикселями.

Внутри системы Google Maps JavaScript API вся поверхность карты проецируется на квадрат фиксированного размера при zoom = 0:

  • 256 × 256 пикселей

Каждое увеличение zoom удваивает масштаб:

  • zoom 1 → 512 × 512
  • zoom 2 → 1024 × 1024
  • zoom n → 256 × 2ⁿ

Таким образом, координата точки вычисляется как:

  • worldX = (longitude + 180) / 360 × tileSize × scale
  • worldY = transformation( latitude ) × tileSize × scale

где scale = 2^zoom.


Пиксельные координаты карты

Пиксельная система используется для позиционирования элементов на экране относительно контейнера карты.

В Google Maps JavaScript API пиксели делятся на два типа:

  • глобальные пиксели (global pixels) — относительно всей карты на данном zoom
  • локальные пиксели (container pixels) — относительно DOM-контейнера

Глобальные пиксели вычисляются из world coordinates:

  • pixelX = worldX
  • pixelY = worldY

Локальные пиксели:

  • localPixel = globalPixel − topLeftCornerOfVisibleMap

Эта разница критична при работе с кастомными overlay.


Преобразование через Projection API

Для работы с координатами используется объект Projection, доступный через OverlayView.

Основные методы:

fromLatLngToPoint()

Преобразует географические координаты в мировые координаты.

const projection = overlay.getProjection();

const point = projection.fromLatLngToPoint(
  new google.maps.LatLng(55.751244, 37.618423)
);

Результат:

  • x — позиция по горизонтали
  • y — позиция по вертикали

Эти значения зависят от текущего zoom и масштаба карты.


fromPointToLatLng()

Обратное преобразование:

const latLng = projection.fromPointToLatLng(
  new google.maps.Point(200, 300)
);

Используется при:

  • обработке кликов по кастомным слоям
  • преобразовании координат оверлеев
  • синхронизации графики и карты

Масштабирование и зависимость от zoom

Ключевая особенность системы координат заключается в экспоненциальном росте детализации.

Фактически:

  • один пиксель при zoom 0 покрывает огромную географическую область
  • при каждом увеличении zoom детализация удваивается

Это влияет на все преобразования:

  • world coordinates масштабируются линейно
  • pixel coordinates зависят от размера viewport
  • lat/lng остаются неизменными

Тайловая система координат

Карта разбивается на квадратные тайлы размером 256×256 пикселей.

Формулы:

  • tileX = floor(pixelX / 256)
  • tileY = floor(pixelY / 256)

Эта система используется для:

  • подгрузки картографических данных
  • оптимизации рендеринга
  • кеширования изображений

Внутри Google Maps JavaScript API тайлы подгружаются динамически в зависимости от области видимости.


Преобразование координат при работе с оверлеями

При создании кастомных слоёв используется наследование от OverlayView.

Типичный цикл преобразования:

  1. LatLng → world point
  2. world point → pixel position
  3. pixel position → DOM coordinates

Пример логики позиционирования:

draw() {
  const projection = this.getProjection();

  const position = projection.fromLatLngToPoint(this.latlng);

  const scale = Math.pow(2, this.map.getZoom());

  const pixel = new google.maps.Point(
    position.x * scale,
    position.y * scale
  );

  const offset = this.map.getDiv().getBoundingClientRect();

  this.div.style.left = (pixel.x - offset.left) + "px";
  this.div.style.top = (pixel.y - offset.top) + "px";
}

Сдвиг центра карты и перерасчёт координат

Любое изменение центра карты приводит к пересчёту всех пиксельных координат относительно нового origin.

Алгоритм:

  • вычисляется новый top-left world coordinate
  • все объекты смещаются на разницу
  • DOM обновляется без изменения LatLng

Это позволяет:

  • плавно перемещать карту
  • сохранять консистентность слоёв
  • минимизировать перерасчёты геометрии

Работа с событиями и координатами мыши

При взаимодействии с картой координаты курсора доступны в двух формах:

  • pixel coordinates (относительно контейнера)
  • LatLng (географические)
map.addListener("click", (event) => {
  console.log(event.latLng.lat());
  console.log(event.latLng.lng());
});

Внутренне происходит:

  • mouseEvent → pixel position
  • pixel position → world coordinate
  • world coordinate → LatLng

Погрешности и особенности округления

При высоких zoom уровнях возможны небольшие расхождения между координатами из-за:

  • ограничений точности float
  • особенностей Web Mercator
  • округления пиксельных значений

В Google Maps JavaScript API это компенсируется внутренними оптимизациями рендеринга и кеширования.


Использование кастомных преобразований

В ряде случаев требуется ввод собственной системы координат:

  • игровые карты поверх Google Maps
  • геопривязанные графические слои
  • тепловые карты высокой плотности

Тогда используется цепочка:

  • LatLng → Projection → custom transform → render coordinates

Это позволяет интегрировать любые визуальные модели поверх базовой карты без потери синхронизации с географией.