containerPointToLatLng и latLngToContainerPoint

Leaflet работает с несколькими уровнями координат одновременно, и ключевая сложность при разработке интерактивных карт заключается в постоянном преобразовании между географическими координатами и экранными координатами. Одной из центральных пар методов, обеспечивающих это преобразование на уровне контейнера карты, являются containerPointToLatLng и latLngToContainerPoint.

Внутренняя модель карты разделяется на несколько систем координат:

  • LatLng (географические координаты) — широта и долгота.
  • Point (пиксельные координаты слоя карты) — координаты в проекции карты на текущем масштабе.
  • Container Point (координаты контейнера) — пиксели относительно DOM-элемента карты.

Контейнерный уровень является связующим звеном между DOM-событиями и географической моделью. Именно здесь происходят преобразования для кликов, перетаскиваний и позиционирования пользовательских элементов.

latLngToContainerPoint

Метод latLngToContainerPoint(latlng, zoom?) преобразует географические координаты в координаты относительно контейнера карты.

Сигнатура

map.latLngToContainerPoint(latlng, zoom?)

Поведение

Алгоритм преобразования включает несколько шагов:

  1. Географические координаты переводятся в пиксели мировой проекции (world coordinates).
  2. Учитывается текущий масштаб карты (zoom).
  3. Применяется смещение центра карты (map.getPixelOrigin()).
  4. Результат нормализуется относительно верхнего левого угла контейнера.

Итогом является точка, которая соответствует позиции элемента на экране внутри контейнера карты.

Пример использования

const latlng = L.latLng(51.505, -0.09);
const point = map.latLngToContainerPoint(latlng);

console.log(point.x, point.y);

Практическое применение

  • позиционирование HTML-оверлеев над маркерами;
  • вычисление координат для кастомных tooltip;
  • синхронизация canvas-аннотаций с географическими объектами;
  • построение пользовательских слоёв поверх карты.

Особенности

При вызове без указания zoom используется текущий масштаб карты. Это важно, так как результат зависит от состояния карты в момент вычисления. При анимациях zoom результат может отличаться в зависимости от фазы перехода.

containerPointToLatLng

Метод containerPointToLatLng(point, zoom?) выполняет обратное преобразование: из координат контейнера в географические координаты.

Сигнатура

map.containerPointToLatLng(point, zoom?)

Поведение

Преобразование проходит обратный путь:

  1. Координаты контейнера переводятся в систему пикселей карты.
  2. Учитывается смещение центра и текущая проекция.
  3. Пиксельные координаты конвертируются обратно в LatLng через обратную проекцию.

Результатом является географическая точка, соответствующая позиции на экране.

Пример использования

map.on('click', function (e) {
    const latlng = map.containerPointToLatLng(e.containerPoint);
    console.log(latlng.lat, latlng.lng);
});

Практическое применение

  • обработка кликов по карте с точным получением координат;
  • построение пользовательских инструментов рисования;
  • вычисление географических областей выделения;
  • привязка DOM-интерактивных элементов к карте.

Взаимосвязь методов

Оба метода являются взаимно обратными при одинаковом zoom:

const latlng = L.latLng(52.52, 13.405);

const point = map.latLngToContainerPoint(latlng);
const restoredLatLng = map.containerPointToLatLng(point);

console.log(restoredLatLng); // близко к исходному значению

Однако важно учитывать численные погрешности, возникающие из-за:

  • округления пиксельных значений;
  • плавающей точности при проекциях;
  • трансформаций CSS при анимациях.

Контейнерные координаты и DOM-события

DOM-события Leaflet уже предоставляют containerPoint:

  • e.containerPoint — координаты клика относительно контейнера;
  • e.latlng — сразу рассчитанные географические координаты;
  • e.layerPoint — координаты в системе слоя.

Разница между ними принципиальна:

  • layerPoint зависит от внутренней системы тайлов;
  • containerPoint зависит от размеров и позиции контейнера;
  • latlng — итоговое географическое представление.

Влияние размера контейнера

Размер контейнера напрямую влияет на результат преобразований. При изменении размеров карты:

map.invalidateSize();

происходит пересчёт внутреннего смещения, и все дальнейшие вызовы latLngToContainerPoint начинают использовать новые границы.

Если не вызвать invalidateSize, координаты могут быть смещены из-за несоответствия DOM-реальности и внутреннего состояния карты.

Применение в кастомных слоях

При создании пользовательских слоёв (Canvas, WebGL, SVG поверх карты) часто требуется синхронизация географических координат с пиксельной сеткой.

Пример Canvas-слоя

function drawPoint(latlng) {
    const ctx = canvas.getContext('2d');
    const point = map.latLngToContainerPoint(latlng);

    ctx.beginPath();
    ctx.arc(point.x, point.y, 5, 0, Math.PI * 2);
    ctx.fill();
}

Каждое обновление карты требует перерасчёта всех точек, так как контейнерные координаты изменяются при pan и zoom.

Панорамирование и зум

При изменении положения карты:

  • центр смещается → меняется pixelOrigin;
  • масштаб пересчитывается → изменяется scale factor;
  • все containerPoint становятся невалидными до пересчёта.

Поэтому любые кешированные результаты latLngToContainerPoint требуют обновления при событиях:

  • move
  • zoom
  • resize

Типичные ошибки

Кеширование координат без обновления

Сохранение результата latLngToContainerPoint без учёта движения карты приводит к смещению объектов.

Игнорирование zoom-параметра

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

Использование containerPoint вне контекста карты

containerPoint всегда привязан к конкретному экземпляру карты и его DOM-контейнеру; использование вне этого контекста лишено смысла.

Геометрическая интерпретация

С точки зрения математики:

  • latLngToContainerPoint — композиция проекции + аффинного преобразования (scale + translate);
  • containerPointToLatLng — обратное преобразование с использованием inverse projection.

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

Использование в сложных взаимодействиях

В задачах вроде:

  • drag-and-drop геообъектов,
  • построения геофенсингов,
  • интерактивного редактирования полигонов,

эти методы выступают базовым мостом между UI и геоданными. Любое перемещение мыши сначала выражается в containerPoint, а затем преобразуется в LatLng для сохранения модели данных.

map.on('mousemove', function (e) {
    const latlng = map.containerPointToLatLng(e.containerPoint);
    updateGeometry(latlng);
});

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