В веб-картографии пересечение границ возникает в момент, когда отображаемые объекты выходят за пределы допустимого диапазона координат или пересекают критические линии системы координат, прежде всего линию антимеридиана (±180° долготы). В Leaflet, основанном на Web Mercator (EPSG:3857), такие ситуации требуют особого поведения карты, тайлов и векторных слоёв, поскольку стандартная линейная интерполяция координат приводит к визуальным разрывам и искажениям.
Антимеридиан — линия долготы 180°, разделяющая восточное и западное полушария. При построении линий или полигонов, пересекающих эту границу, координаты резко скачут:
В Leaflet это проявляется при работе с объектами
L.polyline, L.polygon, GeoJSON и любыми
наборами координат, не нормализованными к одному «окну мира».
Leaflet использует систему координат L.CRS.EPSG3857, где
долгота и широта проецируются в плоское пространство. Однако сама модель
мира в этой проекции допускает повторение карты по оси X.
Ключевой механизм — «зацикливание мира» (world wrapping). Долгота фактически интерпретируется по модулю 360°:
Это позволяет тайлам бесшовно повторяться по горизонтали, но создаёт сложности для геометрии.
Тайловые слои в Leaflet по умолчанию поддерживают бесконечное повторение мира:
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
noWrap: false
}).addTo(map);
При noWrap: false карта дублируется по горизонтали,
создавая эффект непрерывного мира. При этом один и тот же объект может
визуально существовать в нескольких копиях карты одновременно.
При noWrap: true повторение отключается, и карта
обрезается по границам проекции, что устраняет дублирование, но
усиливает проблемы при пересечении антимеридиана.
Механизм worldCopyJump управляет поведением
перетаскивания карты при пересечении границы мира.
const map = L.map('map', {
worldCopyJump: true
});
При включении этой опции:
Без этой опции карта может визуально повторяться, но логика центра сохраняется в исходных координатах, что приводит к скачкам при pan/zoom.
Пересечение границ часто требует жёсткого ограничения пространства карты:
const bounds = L.latLngBounds(
L.latLng(-85, -180),
L.latLng(85, 180)
);
const map = L.map('map', {
maxBounds: bounds,
maxBoundsViscosity: 1.0
});
maxBounds фиксирует допустимую область перемещения.
Параметр maxBoundsViscosity определяет «жёсткость»
ограничения:
Такая конфигурация устраняет возможность пересечения антимеридиана пользователем, но не решает геометрические проблемы внутри данных.
При построении линии между точками с долготой 179° и -179° Leaflet соединяет их напрямую через весь слой карты. Это приводит к артефакту — длинной линии через всю проекцию.
Пример проблемной геометрии:
const line = L.polyline([
[10, 179],
[10, -179]
]).addTo(map);
Визуально это выглядит как пересечение всего мира, а не короткий путь через Тихий океан.
Решение заключается в разбиении сегмента на два:
Leaflet не выполняет это автоматически для произвольных геометрий, поэтому требуется предобработка координат.
GeoJSON-объекты особенно чувствительны к пересечению границ. Полигон, пересекающий антимеридиан, может быть интерпретирован как самопересекающийся или некорректный.
Пример проблемного полигона:
const polygon = {
"type": "Polygon",
"coordinates": [[
[178, 10],
[-178, 10],
[-178, 20],
[178, 20],
[178, 10]
]]
};
L.geoJSON(polygon).addTo(map);
В зависимости от интерпретации, такой объект может «растягиваться» через всю карту.
Корректная обработка требует нормализации:
Web Mercator искажает пространство при приближении к полюсам, но сохраняет линейность по долготе. Именно это делает антимеридиан особым случаем: разрыв возникает не из-за проекции, а из-за дискретности диапазона [-180, 180].
В Leaflet координаты внутри слоя приводятся к пиксельным значениям:
При пересечении 180° происходит сброс X-координаты, что и создаёт скачок.
Для отдельных точек применяется нормализация долготы:
const latlng = L.latLng(10, 190);
const wrapped = latlng.wrap();
Метод приводит координату к ближайшему эквиваленту в диапазоне карты. Это особенно важно при динамическом обновлении объектов:
Без нормализации маркер может исчезать при пересечении границы и появляться с другой стороны мира.
При вычислении границ карты Leaflet использует минимальный bounding box. Однако при наличии координат по обе стороны антимеридиана прямоугольник становится некорректным:
const bounds = L.latLngBounds([
[10, 179],
[10, -179]
]);
map.fitBounds(bounds);
Результат может включать весь мир, так как алгоритм не всегда определяет «короткое» расстояние через 180° как предпочтительное.
Для корректного поведения требуется предварительное смещение координат в единое пространство долготы.
Практическая стратегия обработки пересечений заключается в разбиении геометрии:
Логика разбиения для линии:
Такой подход сохраняет визуальную целостность и предотвращает артефакты.
При включённом повторении мира один и тот же объект может отображаться несколько раз. Leaflet создаёт копии слоя в соседних «мирах»:
Это особенно заметно для:
Для устранения эффекта применяется фиксация слоя на одной копии мира или отключение wrapping.
События карты (click, mousemove) возвращают координаты уже в нормализованном виде. Однако при пересечении границы возможно несоответствие между:
Это приводит к эффектам:
Решение связано с синхронизацией wrap-логики для всех слоёв карты.