В этом занятии мы научимся создавать интернет-страницу, в которою будет встроена карта вашего района.
Для работы нам понадобится текстовый редактор (блокнот). Рекомендую вместо стандартного блокнота использовать программу Notepad++. Для вставки карты на сайт мы будем использовать JavaScript библиотеку с открытым исходным кодом Leaflet. Также потребуется проект QGIS по району города.
Создадим новый текстовый документ формата .txt и добавим в него следующий html-код:
Это начальная структура любого сайта. Далее следует сохранить и закрыть текстовый документ. Сменить расширение файла с .txt на .html (в свойствах папок должен быть установлен показ расширений файлов) и открыть файл в браузере.
Для использования Leaflet на вашем сайте необходимо в заголовок сайта (head) добавить ссылки на CSS-стили и код Leaflet:
-
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.2.0/dist/leaflet.css"
-
integrity="sha512-M2wvCLH6DSRazYeZRIm1JnYyh22purTM+FDB5CsyxtQJYeKq83arPe5wgbNmcFXGqiSH2XR8dT/fJISVA1r/zQ=="
-
crossorigin=""/>
-
<script src="https://unpkg.com/leaflet@1.2.0/dist/leaflet.js"
-
integrity="sha512-lInM/apFSqyy1o6s89K4iQUKg6ppXEgsVxT35HbzUupEVRh2Eu9Wdl4tHj7dZO0s1uvplcYGmt3498TtHq+log=="
-
crossorigin=""></script>
В тело сайта (body) нужно добавить div-элемент с id=map и заданными размерами:
Создаем блок script в теле сайта. Итоговый html-код представлен ниже:
-
<html>
-
<head>
-
-
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.2.0/dist/leaflet.css"
-
integrity="sha512-M2wvCLH6DSRazYeZRIm1JnYyh22purTM+FDB5CsyxtQJYeKq83arPe5wgbNmcFXGqiSH2XR8dT/fJISVA1r/zQ=="
-
crossorigin=""/>
-
<script src="https://unpkg.com/leaflet@1.2.0/dist/leaflet.js"
-
integrity="sha512-lInM/apFSqyy1o6s89K4iQUKg6ppXEgsVxT35HbzUupEVRh2Eu9Wdl4tHj7dZO0s1uvplcYGmt3498TtHq+log=="
-
crossorigin=""></script>
-
</head>
-
<body>
-
<h1>
-
Заголовок страницы
-
</h1>
-
<p>
-
Текст страницы
-
</p>
-
<script type="text/javascript">
-
//Здесь будет писаться весь дальнейший код
-
</script>
-
</body>
-
</html>
Весь нижеследующий код должен писаться в блок script в теле сайта.
Теперь мы можем инициализировать карту и установить географические координаты центра карты и масштаб:
-
var map = L.map('map').setView([55.753, 37.619], 13);
Мы получили контейнер карты с серым фоном. Теперь надо подключить базовую картографическую подложку. В примере мы будем использовать тайловый слой OSM:
-
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
-
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
-
}).addTo(map);
Маркеры
Добавить стандартный маркер на карту:
-
L.marker([51.5, -0.09]).addTo(map)
-
.bindPopup('A pretty CSS3 popup.<br> Easily customizable.')
-
.openPopup();
Стилизованный маркер:
Чтобы создать собственный маркер, необходимо два изображения — изображение маркера и изображение его тени. Формат изображения png с прозрачным фоном.
Стиль маркера в Leaflet определяется объектами L.Icon, которые передаются в качестве опции при создании маркеров. Создадим собственную иконку:
-
var greenIcon = L.icon({
-
iconUrl: 'leaf-green.png',
-
shadowUrl: 'leaf-shadow.png',
-
-
iconSize: [38, 95], // размер значка
-
shadowSize: [50, 64], // размер тени
-
iconAnchor: [22, 94], // точка привязки значка
-
shadowAnchor: [4, 62], // точка привязки тени
-
popupAnchor: [-3, -76] // точка указателя всплывающего меню
-
});
Разместим маркер на карте:
-
L.marker([51.5, -0.09], {icon: greenIcon}).addTo(map);
Работа с GeoJson
Добавить геометрию из файла geojson:
В QGIS сохраняем слой границ как bound.geojson
Открываем файл bound.geojson в текстовом редакторе, в начале файла объявляем переменную adm. Сохраняем файл. Пример файла с объявленной переменной*:
-
var adm = {
-
"type": "FeatureCollection",
-
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
-
"features": [
-
//массив объектов слоя
-
]
-
}
*это не совсем корректно, т.к. измененный geojson не будет открываться в ГИС, но такой подход позволяет работать с геометрией geojson локально, без использования сервера.
Подключаем в заголовке сайта (head) файл bound.geojson (файл должен располагаться в одной папке со страницей сайта):
Добавляем слой geoJson (хранится в объявленной переменной adm) на карту:
-
L.geoJson(adm).addTo(map);
Для стилизации слоя используется атрибут style:
-
var myStyle = {
-
"color": "#ff7800", //цвет линии
-
"weight": 5, //ширина линии в px
-
"opacity": 0.65, //непрозрачность линии
-
"dashArray": '3,5', //пунктирная линия
-
"lineJoin": 'miter', //стиль соединения в углах, по умолчанию 'round'
-
"lineCap": 'square' //стиль законцовок, по умолчанию 'round'
-
"fillColor": "#800026", //цвет фона
-
"fillOpacity": 0.65 //непрозрачность фона
-
};
-
-
L.geoJSON(adm, {
-
style: myStyle
-
}).addTo(map);
Добавить всплывающее окно по клику на объекте (в слое adm должно быть поле popupContent с содержимым всплывающего окна, например: "Привет!"):
-
function onEachFeature(feature, layer) {
-
if (feature.properties && feature.properties.popupContent) {
-
layer.bindPopup(feature.properties.popupContent);
-
}
-
}
-
-
L.geoJSON(adm, {
-
onEachFeature: onEachFeature
-
}).addTo(map);
Добавление события при клике по объекту (в примере по клику на объект карта перемещается к объекту):
-
function zoomToFeature(e) {
-
map.fitBounds(e.target.getBounds());
-
}
-
-
function onEachFeature(feature, layer) {
-
layer.on({click: zoomToFeature});
-
}
-
-
geojson = L.geoJson(adm, {
-
onEachFeature: onEachFeature
-
}).addTo(map);
Группы слоев
Предположим, у вас есть несколько слоев, которые вы хотите объединить в группу, чтобы обрабатывать их как один в своем коде:
-
var littleton = L.marker([39.61, -105.02]).bindPopup('This is Littleton, CO.'),
-
denver = L.marker([39.74, -104.99]).bindPopup('This is Denver, CO.'),
-
aurora = L.marker([39.73, -104.8]).bindPopup('This is Aurora, CO.'),
-
golden = L.marker([39.77, -105.23]).bindPopup('This is Golden, CO.');
Вместо добавления их непосредственно на карту вы можете сделать следующее, используя класс LayerGroup:
-
var cities = L.layerGroup([littleton, denver, aurora, golden]);
Теперь слой cities, объединяющий маркеры городов в один слой, который можно сразу добавить или удалить с карты.
Управление слоями
Leaflet имеет приятный небольшой элемент управления, который позволяет пользователям контролировать, какие слои они видят на карте.
Существует два типа слоев: базовые слои, которые являются взаимоисключающими (на карте одновременно может быть виден только один), например картографические основы, и (2) наложения, которые представляют собой тематические элементы, которые отображаются поверх базового слоя.
Создание базовых слоев:
-
var osm = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
-
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
-
}).addTo(map);
-
-
var osmHOT = L.tileLayer('https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', {
-
maxZoom: 19,
-
attribution: '© OpenStreetMap contributors, Tiles style by Humanitarian OpenStreetMap Team hosted by OpenStreetMap France'});
Далее создадим два объекта. Один будет содержать наши базовые слои, а другой — тематические объекты.
-
var baseMaps = {
-
"OpenStreetMap": osm,
-
"OpenStreetMap.HOT": osmHOT
-
};
-
-
var overlayMaps = {
-
"Cities": cities
-
};
Теперь все, что осталось сделать, это создать элемент управления слоями и добавить его на карту.
-
var layerControl = L.control.layers(baseMaps, overlayMaps).addTo(map);
Возможно стилизовать клавиши объектов для слоев. Например, этот код сделает метку карты OpenStreetMap.HOT красной:
-
var baseMaps = {
-
"OpenStreetMap": osm,
-
"<span style='color: red'>OpenStreetMap.HOT</span>": osmHOT
-
};
Работа с событиями
Каждый раз, когда что-то происходит в Leaflet, например, пользователь нажимает на маркер или изменяется масштаб карты, соответствующий объект отправляет событие, на которое вы можете подписаться с помощью функции. Он позволяет реагировать на взаимодействие с пользователем, например: открывается окно с координатами при клике на карту:
-
var popup = L.popup();
-
-
function onMapClick(e) {
-
popup
-
.setLatLng(e.latlng)
-
.setContent("Координаты клика: " + e.latlng.toString())
-
.openOn(map);
-
}
-
-
map.on('click', onMapClick);