Внутри карты одновременно существуют несколько систем координат, каждая из которых решает свою задачу: географическая (широта/долгота), проекционная (плоские координаты в пикселях), тайловая (индексы тайлов) и координаты слоя (позиции объектов в рамках текущего масштаба и сдвига карты). Преобразование между ними — фундаментальная часть работы карты.
Географические координаты описывают положение точки на поверхности Земли:
В Leaflet они представлены объектом L.LatLng.
const latlng = L.latLng(55.751244, 37.618423);
Этот объект не содержит информации о проекции или масштабе, он описывает только географическую позицию.
Карты не могут отображать сферу напрямую, поэтому используется проекция. По умолчанию применяется Web Mercator:
Проекция в Leaflet реализуется через CRS (Coordinate
Reference System).
const map = L.map('map', {
crs: L.CRS.EPSG3857
});
Переход от LatLng к проекционным координатам выполняется
через project:
const point = map.options.crs.project(L.latLng(55.75, 37.61));
Результат — координаты в «мировой системе» (world coordinates), выраженные в пикселях при zoom = 0.
Обратное преобразование:
const latlng = map.options.crs.unproject(point);
После проекции координаты становятся линейными и удобными для масштабирования.
Особенности:
Ключевое преобразование в Leaflet:
map.latLngToLayerPoint(latlng);
Пример:
const point = map.latLngToLayerPoint([55.75, 37.61]);
console.log(point.x, point.y);
const latlng = map.layerPointToLatLng(L.point(200, 300));
Это важно при обработке событий:
Leaflet оперирует не только географией, но и «слоем» (layer space), который зависит от:
Координаты слоя — это смещение относительно верхнего левого угла видимой области.
const layerPoint = map.latLngToLayerPoint(latlng);
Масштабирование карты — это изменение коэффициента преобразования между мировыми и экранными координатами.
Формула масштабирования:
scale = 2^zoom
В Leaflet это используется внутри:
map.getZoomScale(toZoom, fromZoom);
Пример:
const scale = map.getZoomScale(10, 8); // 4
Низкоуровневое преобразование координат реализуется через
L.Transformation:
const t = new L.Transformation(1, 0, -1, 0);
Формально:
x' = a * x + b
y' = c * y + d
Используется для:
Карты состоят из квадратных тайлов 256×256 пикселей.
Для получения тайла используется:
const tilePoint = map.project(latlng, zoom)
.divideBy(256)
.floor();
Каждый тайл имеет:
Долгота может выходить за диапазон [-180, 180], поэтому применяется нормализация:
const wrapped = map.wrapLatLng(L.latLng(10, 200));
Результат:
Это важно для бесшовного повторения карты по горизонтали.
Положение карты в пикселях зависит от origin:
const origin = map.getPixelOrigin();
И вычисление позиции:
const point = map.project(latlng, map.getZoom())
.subtract(origin);
При обработке событий координаты приходят в экранной системе:
map.on('click', (e) => {
const latlng = e.latlng;
const point = e.layerPoint;
});
Здесь:
latlng — географические координатыlayerPoint — пиксели слояLeaflet поддерживает замену системы координат:
const crs = L.CRS.Simple;
const map = L.map('map', {
crs: crs
});
CRS.Simple:
Расстояния вычисляются через геодезическую модель:
const d = latlng1.distanceTo(latlng2);
Результат — метры.
Алгоритм учитывает кривизну Земли.
Каждый слой карты имеет свою систему координат:
Marker позиционируется через преобразование:
const pos = map.latLngToLayerPoint(marker.getLatLng());
marker._icon.style.transform = `translate(${pos.x}px, ${pos.y}px)`;
Полное преобразование можно представить как комбинацию:
screenPoint = (project(latlng) * scale) - origin
Где:
Для обратного расчёта:
latlng = unproject((screenPoint + origin) / scale)
В Leaflet:
map.containerPointToLatLng(point);
Есть три уровня координат:
containerPoint — относительно DOM контейнераlayerPoint — относительно слоя картыlatlng — географические координатыПреобразования:
map.containerPointToLatLng(point);
map.latLngToContainerPoint(latlng);
Web Mercator не поддерживает:
Поэтому все преобразования остаются аффинными и сохраняют линейную структуру.
При каждом изменении масштаба происходит:
map.on('zoom', () => {
const z = map.getZoom();
});
Внутреннюю модель можно представить как цепочку:
LatLng
→ Projection (world coords)
→ Zoom scaling
→ Origin shift
→ Layer point
→ Container point
Каждый этап строго детерминирован и обратим, что позволяет точно синхронизировать географию, пиксели и визуальные элементы карты.