Leaflet работает с несколькими уровнями координат одновременно, и
ключевая сложность при разработке интерактивных карт заключается в
постоянном преобразовании между географическими координатами и экранными
координатами. Одной из центральных пар методов, обеспечивающих это
преобразование на уровне контейнера карты, являются
containerPointToLatLng и
latLngToContainerPoint.
Внутренняя модель карты разделяется на несколько систем координат:
Контейнерный уровень является связующим звеном между DOM-событиями и географической моделью. Именно здесь происходят преобразования для кликов, перетаскиваний и позиционирования пользовательских элементов.
Метод latLngToContainerPoint(latlng, zoom?) преобразует
географические координаты в координаты относительно контейнера
карты.
map.latLngToContainerPoint(latlng, zoom?)
Алгоритм преобразования включает несколько шагов:
Итогом является точка, которая соответствует позиции элемента на экране внутри контейнера карты.
const latlng = L.latLng(51.505, -0.09);
const point = map.latLngToContainerPoint(latlng);
console.log(point.x, point.y);
При вызове без указания zoom используется текущий масштаб карты. Это важно, так как результат зависит от состояния карты в момент вычисления. При анимациях zoom результат может отличаться в зависимости от фазы перехода.
Метод containerPointToLatLng(point, zoom?) выполняет
обратное преобразование: из координат контейнера в географические
координаты.
map.containerPointToLatLng(point, zoom?)
Преобразование проходит обратный путь:
Результатом является географическая точка, соответствующая позиции на экране.
map.on('click', function (e) {
const latlng = map.containerPointToLatLng(e.containerPoint);
console.log(latlng.lat, latlng.lng);
});
Оба метода являются взаимно обратными при одинаковом zoom:
const latlng = L.latLng(52.52, 13.405);
const point = map.latLngToContainerPoint(latlng);
const restoredLatLng = map.containerPointToLatLng(point);
console.log(restoredLatLng); // близко к исходному значению
Однако важно учитывать численные погрешности, возникающие из-за:
DOM-события Leaflet уже предоставляют
containerPoint:
e.containerPoint — координаты клика относительно
контейнера;e.latlng — сразу рассчитанные географические
координаты;e.layerPoint — координаты в системе слоя.Разница между ними принципиальна:
layerPoint зависит от внутренней системы тайлов;containerPoint зависит от размеров и позиции
контейнера;latlng — итоговое географическое представление.Размер контейнера напрямую влияет на результат преобразований. При изменении размеров карты:
map.invalidateSize();
происходит пересчёт внутреннего смещения, и все дальнейшие вызовы
latLngToContainerPoint начинают использовать новые
границы.
Если не вызвать invalidateSize, координаты могут быть
смещены из-за несоответствия DOM-реальности и внутреннего состояния
карты.
При создании пользовательских слоёв (Canvas, WebGL, SVG поверх карты) часто требуется синхронизация географических координат с пиксельной сеткой.
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.
При изменении положения карты:
Поэтому любые кешированные результаты
latLngToContainerPoint требуют обновления при событиях:
movezoomresizeСохранение результата latLngToContainerPoint без учёта
движения карты приводит к смещению объектов.
Передача устаревшего zoom в методы приводит к несовпадению визуального положения и географической точки.
containerPoint всегда привязан к конкретному экземпляру карты и его DOM-контейнеру; использование вне этого контекста лишено смысла.
С точки зрения математики:
latLngToContainerPoint — композиция проекции +
аффинного преобразования (scale + translate);containerPointToLatLng — обратное преобразование с
использованием inverse projection.Фактически карта представляет собой динамическую декартову систему координат, где начало координат фиксируется в левом верхнем углу контейнера и постоянно пересчитывается при взаимодействии пользователя с картой.
В задачах вроде:
эти методы выступают базовым мостом между UI и геоданными. Любое перемещение мыши сначала выражается в containerPoint, а затем преобразуется в LatLng для сохранения модели данных.
map.on('mousemove', function (e) {
const latlng = map.containerPointToLatLng(e.containerPoint);
updateGeometry(latlng);
});
Такая схема обеспечивает разделение логики отображения и хранения данных, что критично для масштабируемых картографических приложений.