Русский
Русский
English
Статистика
Реклама

JavaScript за 60 секунд работаем с картой (Geolocation API, Leaflet.js, Nominatim)



Доброго времени суток, друзья!

В этом небольшом туториале мы вместе с вами выполним три простых задания:

  • С помощью Geolocation API и Leaflet.js определим текущее местоположение пользователя и отобразим его на карте
  • Реализуем анимированный переход между городами
  • Реализуем переключение между адресами с предварительным получением названия объекта и его координат

Код проекта находится здесь.

Поиграть с кодом можно здесь:


Определяем текущее местоположение пользователя


Geolocation API позволяет пользователю предоставлять веб-приложению данные о своем местоположении. В приложении для запроса этих данных используется метод Geolocation.getCurrentPosition(). Данный метод принимает один обязательный и два опциональных параметра: success функция обратного вызова, получающая объект Position при предоставлении разрешения, error функция обратного вызова, получающая объект PositionError при отказе в доступе, и options объект с настройками. Вот как это выглядит в коде:

navigator.geolocation.getCurrentPosition(success, error, {  // высокая точность  enableHighAccuracy: true})function success({ coords }) {  // получаем широту и долготу  const { latitude, longitude } = coords  const position = [latitude, longitude]  console.log(position) // [широта, долгота]}function error({ message }) {  console.log(message) // при отказе в доступе получаем PositionError: User denied Geolocation}

Отображаем местоположение пользователя на карте


В качестве карты мы будем использовать Leaflet.js. Данный сервис является альтернативой Google Maps и OpenStreetMap, уступает им по функционалу, но подкупает простотой интерфейса. Создаем разметку, в которой подключаем стили и скрипт карты:

<head>  <!-- стили карты -->  <link      rel="stylesheet"      href="http://personeltest.ru/aways/unpkg.com/leaflet@1.7.1/dist/leaflet.css"      integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="      crossorigin=""    />    <!-- скрипт карты -->    <script      src="http://personeltest.ru/aways/unpkg.com/leaflet@1.7.1/dist/leaflet.js"      integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="      crossorigin=""    ></script>    <!-- наши стили -->    <link rel="stylesheet" href="style.css" /></head><body>  <!-- контейнер для карты -->  <div id="map"></div>  <!-- кнопка для вызова функции -->  <button id="my_position">My Position</button>  <!-- наш скрипт-модуль -->  <script src="script.js" type="module"></script></body>

Добавляем минимальные стили (style.css):

* {  margin: 0;  padding: 0;  box-sizing: border-box;}body {  min-height: 100vh;  display: grid;  place-content: center;  place-items: center;  background-color: rgb(241, 241, 241);}#map {  width: 480px;  height: 320px;  border-radius: 4px;  box-shadow: 0 0 1px #222;}button {  padding: 0.25em 0.75em;  margin: 1em 0.5em;  cursor: pointer;  user-select: none;}

Создаем модуль map.js следующего содержания:

// создаем локальные переменные для карты и маркера// каждый модуль имеет собственное пространство именlet map = nulllet marker = null// функция принимает позицию - массив с широтой и долготой// и сообщение, отображаемое над маркером (tooltip)export function getMap(position, tooltip) {  // если карта не была инициализирована  if (map === null) {    // второй аргумент, принимаемый методом setView - это масштаб (zoom)    map = L.map('map').setView(position, 15)  } else return  // что-то типа рекламы  // без этого карта работать не будет  L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {    attribution:      ' <a href="http://personeltest.ru/aways/www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'  }).addTo(map)  // добавляем маркер с сообщением  L.marker(position).addTo(map).bindPopup(tooltip).openPopup()}

Наконец, создаем script.js:

// импортируем функциюimport { getMap } from './map.js'// находим кнопку и добавляем к ней обработчикdocument.getElementById('my_position').onclick = () => {  navigator.geolocation.getCurrentPosition(success, error, {    enableHighAccuracy: true  })}function success({ coords }) {  const { latitude, longitude } = coords  const currentPosition = [latitude, longitude]  // вызываем функцию, передавая ей текущую позицию и сообщение  getMap(currentPosition, 'You are here')}function error({ message }) {  console.log(message)}

Открываем index.html в браузере, нажимаем на кнопку, предоставляем разрешение на получение данных о местоположении, видим нашу позицию на карте.



Отлично. Двигаемся дальше.

Анимированный переход между городами


Предположим, что у нас имеется объект с тремя городами (Москва, Санкт-Петербург, Екатеринбург) и их координатами (db/cities.json):

{  "Moscow": {    "lat": "55.7522200",    "lon": "37.6155600"  },  "Saint-Petersburg": {    "lat": "59.9386300",    "lon": "30.3141300"  },  "Ekaterinburg": {    "lat": "56.8519000",    "lon": "60.6122000"  }}

Нам необходимо реализовать плавное переключение между этими городами на карте.

Добавляем в разметку контейнер для городов:

<div id="cities"></div>

Переписываем script.js:

import { getMap } from './map.js'// получаем контейнер для городовconst $cities = document.getElementById('cities');(async () => {  // получаем объект с городами  const response = await fetch('./db/cities.json')  const cities = await response.json()  // перебираем города  for (const city in cities) {    // создаем кнопку    const $button = document.createElement('button')    // текстовое содержимое кнопки - название города    $button.textContent = city    // получаем широту и долготу    const { lat, lon } = cities[city]    // записываем название города, широту и долготу    // в соответствующие data-атрибуты    $button.dataset.city = city    $button.dataset.lat = lat    $button.dataset.lon = lon    // добавляем кнопку в контейнер    $cities.append($button)  }})()// обрабатываем нажатие кнопки$cities.addEventListener('click', ({ target }) => {  // нас интересует только нажатие кнопки  if (target.tagName !== 'BUTTON') return  // получаем название города, широту и долготу из data-атрибутов  const { city, lat, lon } = target.dataset  const position = [lat, lon]  // вызываем функцию, передавая ей позицию и название города  getMap(position, city)})

Также немного изменим map.js:

let map = nulllet marker = nullexport function getMap(position, tooltip) {  if (map === null) {    map = L.map('map').setView(position, 15)  } else {    // перемещение к следующей позиции    map.flyTo(position)  }  L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {    attribution:      ' <a href="http://personeltest.ru/aways/www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'  }).addTo(map)  // удаление предыдущего маркера  if (marker) {    map.removeLayer(marker)  }  marker = new L.Marker(position).addTo(map).bindPopup(tooltip).openPopup()}

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



Плавное переключением между адресами


Предположим, что у нас имеются три объекта с названиями и адресами (db/addresses.json):

{  "Театр драмы": "Октябрьская площадь, 2",  "Театр оперы и балета": "Проспект Ленина, 46А",  "Коляда-Театр": "Проспект Ленина, 97"}

Нам необходимо реализовать переключение между этими объектами на карте. Но как нам это сделать без координат? Никак. Следовательно, нам каким-то образом нужно эти координаты получить. Для этого воспользуемся сервисом Nominatim от OpenStreetMap. О том, как правильно сформировать строку запроса, смотрите здесь. Я продемонстрирую лишь один из возможных вариантов.

Итак, создаем в разметке контейнер для адресов:

<div id="addresses"></div>

Переписываем script.js:

// получаем контейнер для адресовconst $addresses = document.getElementById('addresses');(async () => {  // названия и адреса объектов  const response = await fetch('./db/addresses.json')  const addresses = await response.json()  // для каждого места  for (const place in addresses) {    // создаем кнопку    const $button = document.createElement('button')    $button.textContent = place    // получаем адрес    const address = addresses[place]    // формируем строку запроса    const query = address.replace(      /([А-ЯЁа-яё]+)\s([А-ЯЁа-яё]+),\s([0-9А-ЯЁа-яё]+)/,      '$3+$1+$2,+Екатеринбург'    )    // получаем, например, 2+Октябрьская+площадь,+Екатеринбург    // записываем данные в соответствующие data-атрибуты    $button.dataset.address = address    $button.dataset.query = query    $addresses.append($button)  }})()// обрабатываем нажатие кнопки$addresses.addEventListener('click', async ({ target }) => {  if (target.tagName !== 'BUTTON') return  // получаем данные из data-атрибутов  const { address, query } = target.dataset  // получаем ответ от сервиса  const response = await fetch(    `https://nominatim.openstreetmap.org/search?q=${query}&format=json&limit=1`  )  // format - формат данных, limit - количество объектов с данными  // парсим ответ, извлекая нужные сведения  const { display_name, lat, lon } = (await response.json())[0]  // редактриуем название объекта  const name = display_name.match(/[А-ЯЁа-яё\s(\-)]+/)[0]  const position = [lat, lon]  // формируем сообщение  const tooltip = `${name}<br>${address}`  // вызываем функцию  getMap(position, tooltip)})

Открываем index.html. При нажатии первой кнопки сразу получаем позицию и название театра. При нажатии второй и последующих кнопок плавно перемещаемся между театрами.



Круто. Все работает, как ожидается.

На этом позвольте откланяться. Надеюсь, вы нашли для себя что-нибудь интересное. Благодарю за внимание и хорошего дня.
Источник: habr.com
К списку статей
Опубликовано: 14.12.2020 12:16:00
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Разработка веб-сайтов

Javascript

Программирование

Разработка

Map

Карта

Geolocation api

Geolocation

Геолокация

Определение местоположения

Leaflet.js

Google maps

Openstreetmap

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru