OpenStreetMap

OpenStreetMap (OSM) — свободный картографический проект, представляющий собой открытую географическую базу данных, создаваемую и поддерживаемую сообществом участников по всему миру. Для библиотеки Leaflet OpenStreetMap является наиболее распространённым источником картографических тайлов и часто используется в качестве базового слоя карты.

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


Роль OpenStreetMap в Leaflet

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

Схема взаимодействия выглядит следующим образом:

  1. Leaflet создаёт контейнер карты.
  2. Добавляется тайловый слой.
  3. Leaflet загружает изображения тайлов с серверов OpenStreetMap.
  4. Пользователь видит карту и взаимодействует с ней.

Таким образом, Leaflet является инструментом визуализации, а OpenStreetMap — источником картографической информации.


Подключение OpenStreetMap к карте

После создания объекта карты необходимо добавить тайловый слой.

const map = L.map('map').setView([55.7558, 37.6176], 10);

L.tileLayer(
    'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
    {
        maxZoom: 19,
        attribution: '© OpenStreetMap contributors'
    }
).addTo(map);

В данном примере:

  • {z} — уровень масштабирования;
  • {x} — координата тайла по горизонтали;
  • {y} — координата тайла по вертикали.

Leaflet автоматически подставляет необходимые значения и загружает соответствующие изображения.


Контейнер карты

Перед отображением карты требуется создать HTML-элемент.

<div id="map"></div>

Размеры задаются через CSS:

#map {
    height: 600px;
    width: 100%;
}

Если размеры не определены, карта отображаться не будет, поскольку элемент контейнера окажется нулевой высоты.


Атрибуция OpenStreetMap

При использовании данных OpenStreetMap обязательно указывается ссылка на авторов данных.

Пример корректной атрибуции:

attribution: '&copy; OpenStreetMap contributors'

Полный пример:

L.tileLayer(
    'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
    {
        attribution:
            '&copy; OpenStreetMap contributors',
        maxZoom: 19
    }
);

Атрибуция отображается в правом нижнем углу карты.


Понятие тайлов

Карта состоит из множества небольших изображений одинакового размера, называемых тайлами.

На каждом уровне масштабирования поверхность Земли делится на сетку.

Например:

Масштаб Количество тайлов
0 1
1 4
2 16
3 64
10 более миллиона

При перемещении карты Leaflet загружает только необходимые изображения.

Такой подход обеспечивает:

  • быструю загрузку;
  • экономию трафика;
  • плавную навигацию;
  • возможность масштабирования практически без ограничений.

Изменение начального масштаба

Начальный масштаб задаётся методом setView.

const map = L.map('map').setView(
    [55.7558, 37.6176],
    13
);

Здесь:

  • первая координата — широта;
  • вторая координата — долгота;
  • число 13 — уровень приближения.

Типичные уровни масштаба:

Zoom Назначение
0–3 Мир
4–6 Континенты
7–9 Регионы
10–12 Города
13–16 Районы
17–19 Улицы и здания

Ограничение масштабирования

Leaflet позволяет задавать минимальный и максимальный уровни приближения.

L.tileLayer(
    'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
    {
        minZoom: 5,
        maxZoom: 18
    }
).addTo(map);

Теперь пользователь не сможет выйти за указанные пределы.


Центрирование карты

Изменение центра карты выполняется методом setView.

map.setView(
    [59.9386, 30.3141],
    12
);

Либо методом panTo.

map.panTo(
    [59.9386, 30.3141]
);

Отличие заключается в том, что panTo() создаёт плавную анимацию перемещения.


Определение текущего центра

Получение координат центра карты:

const center = map.getCenter();

console.log(center.lat);
console.log(center.lng);

Результат:

55.7558
37.6176

Получение текущего масштаба

const zoom = map.getZoom();

console.log(zoom);

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


Отслеживание перемещения карты

Событие moveend срабатывает после завершения перемещения.

map.on('moveend', () => {
    console.log('Карта перемещена');
});

Получение нового центра:

map.on('moveend', () => {

    const center = map.getCenter();

    console.log(center.lat);
    console.log(center.lng);

});

Отслеживание изменения масштаба

Событие zoomend возникает после завершения масштабирования.

map.on('zoomend', () => {

    console.log(
        'Текущий масштаб:',
        map.getZoom()
    );

});

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


Определение границ видимой области

OpenStreetMap используется не только для отображения карты, но и как основа для отображения объектов в пределах текущего окна просмотра.

Получение границ:

const bounds = map.getBounds();

Получение координат:

console.log(bounds.getNorth());
console.log(bounds.getSouth());

console.log(bounds.getEast());
console.log(bounds.getWest());

Это особенно полезно при запросах данных с сервера.


Автоматическое масштабирование под область

Leaflet способен автоматически подобрать масштаб так, чтобы определённая территория полностью поместилась в окно карты.

const bounds = [
    [55.70, 37.40],
    [55.90, 37.80]
];

map.fitBounds(bounds);

После вызова метода карта будет центрирована и масштабирована для отображения всей области.


Использование нескольких слоёв OpenStreetMap

Можно подготовить несколько вариантов базовых карт.

const osm = L.tileLayer(
    'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
    {
        attribution:
            '&copy; OpenStreetMap contributors'
    }
);

Создание объекта слоёв:

const baseMaps = {
    "OpenStreetMap": osm
};

L.control.layers(baseMaps).addTo(map);

Позднее в этот объект могут добавляться другие картографические сервисы.


Обработка кликов по карте

OpenStreetMap отображает карту, а Leaflet предоставляет инструменты взаимодействия.

Получение координат клика:

map.on('click', function(e) {

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

});

Результат:

55.75124 37.61856

Полученные координаты могут использоваться для размещения маркеров или отправки данных на сервер.


Добавление маркера на карту OpenStreetMap

L.marker(
    [55.7558, 37.6176]
).addTo(map);

Маркер отображается поверх тайлов OpenStreetMap и остаётся привязанным к указанным координатам независимо от масштаба.


Всплывающие окна поверх OpenStreetMap

L.marker([55.7558, 37.6176])
    .addTo(map)
    .bindPopup('Москва');

Открытие окна сразу после загрузки:

L.marker([55.7558, 37.6176])
    .addTo(map)
    .bindPopup('Москва')
    .openPopup();

Производительность при работе с OpenStreetMap

При разработке крупных картографических приложений рекомендуется:

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

Leaflet эффективно работает с OpenStreetMap даже при значительных объёмах данных, однако производительность во многом зависит от количества отображаемых объектов.


Ограничения публичных серверов OpenStreetMap

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

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

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

Для высоконагруженных проектов обычно используются:

  • собственные тайловые серверы;
  • коммерческие провайдеры карт;
  • CDN-инфраструктура для распространения тайлов.

Координатная система OpenStreetMap

Leaflet по умолчанию работает с системой координат WGS84, которая использует:

  • широту (latitude);
  • долготу (longitude).

Пример координат:

[55.7558, 37.6176]

Значения записываются в порядке:

[широта, долгота]

Это важная особенность, поскольку многие GIS-системы используют обратный порядок.


Полный пример карты OpenStreetMap

<!DOCTYPE html>
<html lang="ru">
<head>

<meta charset="UTF-8">

<link
    rel="stylesheet"
    href="https://unpkg.com/leaflet/dist/leaflet.css"
/>

<style>
#map {
    height: 600px;
}
</style>

</head>
<body>

<div id="map"></div>

<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>

<script>

const map = L.map('map').setView(
    [55.7558, 37.6176],
    12
);

L.tileLayer(
    'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
    {
        attribution:
            '&copy; OpenStreetMap contributors',
        maxZoom: 19
    }
).addTo(map);

L.marker([55.7558, 37.6176])
    .addTo(map)
    .bindPopup('Центр Москвы');

map.on('click', function(e) {

    L.marker(e.latlng)
        .addTo(map)
        .bindPopup(
            e.latlng.lat +
            ', ' +
            e.latlng.lng
        );

});

</script>

</body>
</html>

Данный пример демонстрирует полный цикл работы с OpenStreetMap в Leaflet: создание карты, подключение тайлового слоя, настройку масштаба, добавление маркеров, использование всплывающих окон и обработку пользовательских событий.