Методы layerPointToLatLng и latLngToLayerPoint

В Leaflet работа с геометрией карты опирается на несколько уровней координатных преобразований. Помимо привычных географических координат (широта и долгота), библиотека активно использует промежуточные экранные системы координат, позволяющие корректно отображать объекты на разных масштабах и проекциях.

Одними из ключевых методов низкоуровневого взаимодействия с системой координат слоя являются latLngToLayerPoint и layerPointToLatLng. Эти функции обеспечивают двустороннее преобразование между географическими координатами и координатами слоя (layer points), которые представляют собой пиксельные координаты внутри текущего слоя карты с учётом зума и проекции.


Внутри Leaflet существует несколько уровней представления координат:

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

Разделение важно:

  • LatLng используется для логики данных
  • ContainerPoint — для работы с событиями мыши и DOM
  • LayerPoint — для рендеринга геометрии на слоях (canvas, SVG, custom layers)

Методы latLngToLayerPoint и layerPointToLatLng работают именно с LayerPoint, который является фундаментом для отрисовки объектов внутри системы карты.


latLngToLayerPoint

Метод преобразует географические координаты в координаты слоя.

Сигнатура

map.latLngToLayerPoint(latlng)

Назначение

Преобразует:

LatLng (широта/долгота) → LayerPoint (x, y в пикселях слоя)

Особенности

  • Учитывает текущий zoom
  • Использует внутреннюю проекцию карты (обычно Mercator)
  • Возвращает координаты относительно “world layer” на текущем уровне масштаба
  • Не зависит от положения карты на экране (pan offset не учитывается так же, как в containerPoint)

Принцип работы

Каждая географическая точка проецируется в двумерное пространство, после чего масштабируется в соответствии с уровнем zoom.

Упрощённо:

worldCoordinate = projection(latlng)
layerPoint = worldCoordinate * scale(zoom)

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

const latlng = L.latLng(55.751244, 37.618423);
const point = map.latLngToLayerPoint(latlng);

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

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

1. Кастомный рендеринг через Canvas

При работе с Canvas-слоями необходимо переводить географические координаты в пиксельные:

function drawPoint(ctx, latlng) {
    const point = map.latLngToLayerPoint(latlng);

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

2. Анимация объектов на карте

При изменении позиции объекта в реальном времени:

function moveObject(latlng) {
    const point = map.latLngToLayerPoint(latlng);
    element.style.transform = `translate(${point.x}px, ${point.y}px)`;
}

3. Построение собственных визуальных слоёв

Метод используется при создании кастомных overlay-слоёв, где требуется полный контроль над рендерингом.


layerPointToLatLng

Обратное преобразование: из пиксельных координат слоя в географические координаты.

Сигнатура

map.layerPointToLatLng(point)

Назначение

Преобразует:

LayerPoint (x, y в пикселях слоя) → LatLng (широта/долгота)

Особенности

  • Инверсия latLngToLayerPoint
  • Использует ту же проекцию и zoom
  • Позволяет “считывать” географические координаты из пиксельных позиций слоя

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

const point = L.point(200, 150);
const latlng = map.layerPointToLatLng(point);

console.log(latlng.lat, latlng.lng);

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

1. Обработка пользовательских взаимодействий

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

canvas.addEventListener('click', (e) => {
    const rect = canvas.getBoundingClientRect();

    const layerPoint = L.point(
        e.clientX - rect.left,
        e.clientY - rect.top
    );

    const latlng = map.layerPointToLatLng(layerPoint);

    console.log(latlng);
});

2. Геопривязка пиксельных данных

Если имеется изображение или графический слой, привязанный к карте:

function getGeoFromPixel(x, y) {
    const latlng = map.layerPointToLatLng(L.point(x, y));
    return latlng;
}

3. Реализация собственных инструментов редактирования

При создании редакторов (например, рисование полигонов) важно переводить координаты мыши:

const startLatLng = map.layerPointToLatLng(startPoint);
const endLatLng = map.layerPointToLatLng(endPoint);

Различие между layerPoint и containerPoint

Ключевая ошибка при работе с Leaflet — путаница между системами координат.

layerPoint

  • Привязан к системе карты
  • Учитывает zoom
  • Используется для геометрии слоёв

containerPoint

  • Привязан к DOM контейнеру карты
  • Учитывает только положение карты на экране
  • Используется для событий мыши

Сравнение на практике

map.on('click', (e) => {
    console.log(e.containerPoint); // пиксели в окне
    console.log(e.layerPoint);     // пиксели в системе карты
    console.log(e.latlng);         // географические координаты
});

Связь с системой проекции

Обе функции опираются на внутреннюю проекцию карты.

В большинстве случаев используется:

  • Web Mercator (EPSG:3857)

Проекция преобразует:

(lat, lng) → (x, y) в мировом пространстве

Далее применяется масштабирование:

x, y → layerPoint (с учётом zoom)

Влияние zoom на преобразования

При увеличении масштаба:

  • увеличивается плотность пикселей на единицу координат
  • layerPoint становится более “детализированным”
map.setZoom(10);
const p1 = map.latLngToLayerPoint(latlng);

map.setZoom(15);
const p2 = map.latLngToLayerPoint(latlng);

p1 и p2 будут существенно различаться, хотя LatLng одинаков.


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

При разработке собственных слоёв важно выполнять преобразование в обе стороны:

Рендеринг

const point = map.latLngToLayerPoint(feature.latlng);
draw(point);

Обновление данных

const latlng = map.layerPointToLatLng(point);
updateModel(latlng);

Типичные ошибки при использовании

1. Использование containerPoint вместо layerPoint

Приводит к смещению объектов при zoom.

2. Игнорирование обновления при move/zoom

LayerPoint необходимо пересчитывать при изменении состояния карты:

map.on('move zoom', redraw);

3. Кэширование layerPoint

Нельзя сохранять layerPoint между изменениями zoom:

// неверно
const cached = map.latLngToLayerPoint(latlng);
map.setZoom(12);
// cached устарел

Работа в связке с другими методами

Часто используются вместе:

  • map.latLngToContainerPoint
  • map.containerPointToLatLng
  • map.latLngToLayerPoint
  • map.layerPointToLatLng

Это образует полную систему двусторонних преобразований:

LatLng ↔ ContainerPoint
LatLng ↔ LayerPoint
LayerPoint ↔ LatLng

Геометрические операции через layerPoint

LayerPoint удобен для вычислений:

Расстояния в пикселях

const p1 = map.latLngToLayerPoint(a);
const p2 = map.latLngToLayerPoint(b);

const dx = p1.x - p2.x;
const dy = p1.y - p2.y;

const distance = Math.sqrt(dx * dx + dy * dy);

Построение векторных фигур

const triangle = [
    map.latLngToLayerPoint(a),
    map.latLngToLayerPoint(b),
    map.latLngToLayerPoint(c)
];

Производительность

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

Рекомендации:

  • минимизировать вызовы внутри циклов отрисовки
  • пересчитывать только при изменении zoom/move
  • использовать кэширование геометрии в layerPoint

Роль в архитектуре рендеринга

Внутренний pipeline Leaflet строится вокруг layerPoint как промежуточного представления:

LatLng → World Coordinate → LayerPoint → Rendering (Canvas/SVG/DOM)

И обратный путь:

Event Pixel → LayerPoint → LatLng → Application Logic