Координаты углов

В системе отображения карты Mapbox GL JS каждый кадр представляет собой результат преобразования географических координат в экранное пространство. Центральным элементом этой модели является прямоугольная область canvas, ограниченная четырьмя углами. Эти углы формируют границу видимой области и служат опорными точками для вычисления экстента, взаимодействия с объектами и синхронизации слоёв.

Угловые координаты в контексте Mapbox GL JS выражаются одновременно в двух системах:

  • географическая система координат (longitude/latitude)
  • экранная система координат (pixel space)

Переход между ними осуществляется через проекцию Web Mercator и внутренний трансформационный слой карты.


Основные углы viewport и их логика

Прямоугольная область карты всегда описывается четырьмя ключевыми углами:

  • северо-западный (NW)
  • северо-восточный (NE)
  • юго-западный (SW)
  • юго-восточный (SE)

Каждый угол одновременно существует в двух представлениях:

  • LngLat — долгота и широта
  • Point — пиксельные координаты относительно canvas

Mapbox GL JS предоставляет удобный доступ к границам текущего вида через объект:

const bounds = map.getBounds();

Этот объект типа LngLatBounds содержит минимальные и максимальные значения широты и долготы, которые соответствуют углам текущего отображения.


Получение углов через API карты

Хотя getBounds() возвращает только географический прямоугольник, углы могут быть вычислены явно:

const bounds = map.getBounds();

const nw = bounds.getNorthWest();
const ne = bounds.getNorthEast();
const sw = bounds.getSouthWest();
const se = bounds.getSouthEast();

Каждый метод возвращает объект LngLat, содержащий координаты:

{
  lng: number,
  lat: number
}

Эти значения формируют географическую рамку текущего кадра, независимо от zoom, pitch и bearing.


Проекционные координаты углов

Экранные координаты углов определяются через метод project, преобразующий географическую точку в пиксельное пространство canvas:

const nwPoint = map.project(bounds.getNorthWest());
const nePoint = map.project(bounds.getNorthEast());
const swPoint = map.project(bounds.getSouthWest());
const sePoint = map.project(bounds.getSouthEast());

Результат:

{
  x: number,
  y: number
}

Эта система координат имеет начало в левом верхнем углу canvas, где:

  • x увеличивается вправо
  • y увеличивается вниз

Таким образом, северо-западный угол всегда имеет минимальные значения x и y, а юго-восточный — максимальные.


Обратное преобразование: экран → география

Обратная операция выполняется через unproject, позволяющий получить географические координаты из пиксельной точки:

const lngLat = map.unproject({ x: 0, y: 0 });

Для углов canvas это даёт:

  • (0, 0) → северо-западный угол
  • (width, 0) → северо-восточный угол
  • (0, height) → юго-западный угол
  • (width, height) → юго-восточный угол

Получение размеров canvas:

const canvas = map.getCanvas();
const width = canvas.width;
const height = canvas.height;

Связь углов с системой тайлов

Mapbox GL JS использует тайловую систему, где карта разбита на квадратные фрагменты. Углы viewport определяют набор тайлов, необходимых для отрисовки текущего состояния.

Каждый угол влияет на:

  • выбор тайлов
  • уровень детализации (zoom level)
  • пересечение мировых границ (world wrapping)

При изменении углов пересчитывается набор загружаемых данных:

  • растровые тайлы
  • векторные тайлы
  • GeoJSON источники

Ограничивающий прямоугольник и его свойства

Объект LngLatBounds представляет минимальный bounding box, который полностью охватывает текущую область карты.

const bounds = map.getBounds();

Структура включает:

  • западную долготу (west)
  • южную широту (south)
  • восточную долготу (east)
  • северную широту (north)

В терминах углов:

west = sw.lng = nw.lng
east = se.lng = ne.lng
north = nw.lat = ne.lat
south = sw.lat = se.lat

Эта система упрощает геопространственные вычисления:

  • проверка попадания точки в область
  • фильтрация объектов
  • запросы к backend API

Проверка принадлежности точки углам viewport

Алгоритм определения попадания координаты в текущий экранный прямоугольник:

const bounds = map.getBounds();

function isVisible(lngLat) {
  return bounds.contains(lngLat);
}

Метод contains использует углы NW и SE как границы прямоугольника.


Углы при наклоне и вращении карты

При использовании свойств pitch и bearing геометрия углов усложняется. Хотя географический bounding box остаётся прямоугольным в координатах LngLat, экранное представление становится трапецией.

В этом случае:

  • географические углы остаются фиксированными
  • экранные углы изменяют форму

Пример вычисления экранных углов:

const corners = [
  map.project(bounds.getNorthWest()),
  map.project(bounds.getNorthEast()),
  map.project(bounds.getSouthEast()),
  map.project(bounds.getSouthWest())
];

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


Использование углов для расчёта центра

Центр viewport можно вычислить как среднее между угловыми координатами:

const nw = bounds.getNorthWest();
const se = bounds.getSouthEast();

const center = {
  lng: (nw.lng + se.lng) / 2,
  lat: (nw.lat + se.lat) / 2
};

Однако Mapbox GL JS предоставляет встроенный метод:

map.getCenter();

Который учитывает проекционные искажении и wrapping мира.


Привязка UI элементов к углам

Углы используются для позиционирования интерфейсных элементов:

  • маркеры в углах
  • overlay панели
  • кастомные контролы

Пример закрепления элемента в северо-восточном углу:

const container = map.getContainer();

const element = document.createElement('div');
element.style.position = 'absolute';
element.style.top = '0';
element.style.right = '0';

container.appendChild(element);

Ограничение области отображения через углы

Функция fitBounds напрямую использует углы для вычисления zoom и center:

map.fitBounds([
  [west, south],
  [east, north]
]);

Алгоритм:

  1. вычисление минимального прямоугольника
  2. перевод в экранное пространство
  3. подбор оптимального zoom
  4. установка центра

Углы и события взаимодействия

При кликах и перемещениях курсора координаты события могут быть преобразованы относительно углов viewport:

map.on('click', (e) => {
  const lngLat = e.lngLat;
});

Для анализа положения относительно углов:

const bounds = map.getBounds();

const isTopHalf = lngLat.lat > (bounds.getSouth() + bounds.getNorth()) / 2;
const isLeftHalf = lngLat.lng < (bounds.getWest() + bounds.getEast()) / 2;

Пересечение мирового пространства и углы

При мировом wrapping координаты углов могут выходить за диапазон [-180, 180], однако Mapbox GL JS нормализует значения.

Особенности:

  • несколько копий мира по оси X
  • углы могут пересекать антимеридиан
  • bounds автоматически адаптируется

Пример:

const bounds = map.getBounds();

if (bounds.getEast() < bounds.getWest()) {
  // пересечение антимеридиана
}

Использование углов в пространственном анализе

Углы viewport применяются для:

  • spatial indexing
  • clustering данных
  • server-side tile filtering

Типичный запрос:

const bounds = map.getBounds();

fetch(`/data?bbox=${bounds.toArray().flat().join(',')}`);

Взаимосвязь углов и transform state

Внутренний объект transform карты хранит ключевые параметры:

  • center
  • zoom
  • bearing
  • pitch

Углы являются производными от transform:

transform → projection → corners

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


Итерация по углам для аналитики

Часто требуется обход всех углов viewport:

const corners = [
  map.getBounds().getNorthWest(),
  map.getBounds().getNorthEast(),
  map.getBounds().getSouthEast(),
  map.getBounds().getSouthWest()
];

corners.forEach(corner => {
  console.log(corner.lng, corner.lat);
});

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

  • построения полигона viewport
  • геофенсинга
  • расчёта пересечений

Геометрическая интерпретация углов

В идеализированной модели без проекции углы образуют:

  • прямоугольник в географической системе
  • искажённую четырёхугольную фигуру в экранной системе

Это различие критично при:

  • анализе расстояний
  • вычислении площадей
  • построении heatmap поверхностей

Использование углов для отладки рендеринга

При диагностике отображения карты углы используются для:

  • проверки корректности tile loading
  • анализа clipping области
  • проверки alignment слоёв

Пример логирования:

console.log(map.getBounds().toString());

или детально:

console.table({
  nw: map.getBounds().getNorthWest(),
  ne: map.getBounds().getNorthEast(),
  sw: map.getBounds().getSouthWest(),
  se: map.getBounds().getSouthEast()
});