OpenStreetMap (OSM) — свободный картографический проект, представляющий собой открытую географическую базу данных, создаваемую и поддерживаемую сообществом участников по всему миру. Для библиотеки Leaflet OpenStreetMap является наиболее распространённым источником картографических тайлов и часто используется в качестве базового слоя карты.
В отличие от коммерческих картографических сервисов, OpenStreetMap предоставляет данные по открытой лицензии, что позволяет использовать их в образовательных, исследовательских и коммерческих проектах при соблюдении требований лицензирования.
Leaflet отвечает за отображение карты, управление слоями, маркерами, всплывающими окнами и взаимодействием с пользователем. OpenStreetMap, в свою очередь, предоставляет картографические данные.
Схема взаимодействия выглядит следующим образом:
Таким образом, Leaflet является инструментом визуализации, а 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 обязательно указывается ссылка на авторов данных.
Пример корректной атрибуции:
attribution: '© OpenStreetMap contributors'
Полный пример:
L.tileLayer(
'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
{
attribution:
'© 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
);
Здесь:
Типичные уровни масштаба:
| 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);
После вызова метода карта будет центрирована и масштабирована для отображения всей области.
Можно подготовить несколько вариантов базовых карт.
const osm = L.tileLayer(
'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
{
attribution:
'© 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
Полученные координаты могут использоваться для размещения маркеров или отправки данных на сервер.
L.marker(
[55.7558, 37.6176]
).addTo(map);
Маркер отображается поверх тайлов OpenStreetMap и остаётся привязанным к указанным координатам независимо от масштаба.
L.marker([55.7558, 37.6176])
.addTo(map)
.bindPopup('Москва');
Открытие окна сразу после загрузки:
L.marker([55.7558, 37.6176])
.addTo(map)
.bindPopup('Москва')
.openPopup();
При разработке крупных картографических приложений рекомендуется:
Leaflet эффективно работает с OpenStreetMap даже при значительных объёмах данных, однако производительность во многом зависит от количества отображаемых объектов.
Публичные тайловые серверы предназначены прежде всего для демонстрационных и умеренно нагруженных проектов.
При разработке крупных систем следует учитывать:
Для высоконагруженных проектов обычно используются:
Leaflet по умолчанию работает с системой координат WGS84, которая использует:
Пример координат:
[55.7558, 37.6176]
Значения записываются в порядке:
[широта, долгота]
Это важная особенность, поскольку многие GIS-системы используют обратный порядок.
<!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:
'© 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: создание карты, подключение тайлового слоя, настройку масштаба, добавление маркеров, использование всплывающих окон и обработку пользовательских событий.