Бесплатный вариант геолокации при помощи Open Street Map и Leaflet API мы уже рассматривали в нашей статье . Реализация задачи показать метку с расположением на карте или местонахождение по геолокации — дело простое. Достаточно подключить библиотеки, инициировать карту, задать координаты — и всё, готово. Но этот бесплатный API представляет много других полезных возможностей работы с картами, и одна из них — directions , или автомобильный навигатор (маршрут, расстояние между двумя пунктами).
Перейти к приложению , кликните по картинке:
Вот как автомобильный навигатор работает (в рамках нашей собственной реализации на jQuery ):
VIDEO
Получить API KEY
Чтобы работать с API openrouteservice необходимо зарегистрироватьс я и сгенерировать бесплатный ключ. С ним будут доступны 4 вида функций. Нам как раз нужен Directions (о других вы можете получить информацию на сайте https://openrouteservice.org/).
Получение геокоординат
Чтобы сформировать маршрут, нам нужно получить геокоординаты начального и конечного пунктов. Для этого используем запрос geocode/search
https://api.openrouteservice.org/geocode/search?api_key=${YOUR_API_KEY}&text=$text=Country%20Sity'
В запросе связка страна+город используется для сужения поиска. Запрос можно видоизменять в зависимости от задач. Можно искать начальную и конечную точку внутри населенного пункта, дополнительно указывая улицу, номер дома (address) или штат/регион/область, почтовый индекс и т.д. Подробнее — https://github.com/pelias/documentation/blob/master/structured-geocoding.md#structured-geocoding .
Получение маршрута
Для получения точек маршрута используем запрос directions/driving-car
https://api.openrouteservice.org/v2/directions/driving-car?api_key=${YOUR_API_KEY}&start=lat,lon&end=lat,lon
Изображения карт получаем из Leaflet API.
Основные сложности заключаются в работе с получаемыми файлами JSON. Построить основной маршрут изначально не составляет труда. Единственно нужно придумать способ составления комбинированного запроса (страна+город), чтобы пользователю нужно было как меньше тратить время на ввод. Поэтому сделали вариант выбора страны (город уже вводится пользователем — причем регистр не играет роли).
Но в файле мы получаем ещё и steps — развернутое описание по отрезкам пути. Их мы тоже использовали. Для этого добавили отдельную карту сверху и поле input, в котором пользователь может перемещаться по пути последовательно по шагам (в любом направлении). Как всё это мы реализовали, можете посмотреть в исходном коде ниже. В нем мы изменили способ навигации по шагам (на видео в первом варианте шаги меняются в input) и добавили кнопки before-next.
Чтобы приложение заработало и у вас, в строке 180 нужно вставить свой API KEY.
Смотреть код:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css">
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
<script src="jquery-3.4.1.min.js"></script>
<style>
#take {
display:flex;
justify-content: center;
}
#box,.text-step {
max-width:400px !important;
}
.hidden, .hidden2,.hidden3,.step {
display:none;
margin:20px;
}
.step-count {
text-align: center;
}
#btn-red {
margin:20px;
padding:10px 20px;
background:#215dbf;
border: 1px #215dbf;
outline: 1px #215dbf;
box-shadow: 0 0 3px rgba(0,0,0,0.3);
color:white;
transition:all .3s;
}
#btn-red:hover {
background:#042f75;
box-shadow: 0 0 6px rgba(0,0,0,0.6);
}
.select,.select2{
margin:20px;
}
.select select,.select2 select {
padding:5px;
border:1px solid #4f86e0;
outline:1px solid #4f86e0;
}
#take-place, #take-place2,.step,.step-count {
padding:5px !important;
border:1px solid #4f86e0;
outline:1px solid #4f86e0;
}
#map{border-bottom:2px solid grey}
#btn {width:100px; padding: 5px 10px 5px 10px;background:#3e92e6;color:white;border:1px solid #4f86e0;outline:1px solid #4f86e0;}
#btn:hover {background:#083b6e;color:white;border:1px solid #083b6e;outline:1px solid #083b6e;}
#btn:active {background:#a249ba;color:white;border:1px solid #a249ba;outline:1px solid #a249ba;}
#navigator{display:none;}
</style>
</head>
<body>
<div id="take">
<div id="box">
<div class="select">
<select id="city1" name="sity[]">
<option> Ввыберите страну исходного пункта</option>
<option value="Украина%20">Украина</option>
<option value="Россия%20">Россия</option>
<option value="Беларусь%20">Беларусь</option>
<option value="Польша%20">Польша</option>
<option value="Литва%20">Литва</option>
<option value="Латвия%20">Латвия</option>
<option value="Эстония%20">Эстония</option>
<option value="Молдова%20">Молдова</option>
<option value="Словакия%20">Словакия</option>
<option value="Венгрия%20">Венгрия</option>
<option value="Чехия%20">Чехия</option>
<option value="Германия%20">Германия</option>
<option value="Франция%20">Франция</option>
<option value="Словения%20">Словения</option>
<option value="Болгария%20">Болгария</option>
<option value="Италия%20">Италия</option>
<option value="Грузия%20">Грузия</option>
<option value="Казахстан%20">Казахстан</option>
<option value="Армения%20">Армения</option>
<option value="Дания%20">Дания</option>
<option value="Бельгия%20">Бельгия</option>
<option value="Испания%20">Испания</option>
<option value="Португалия%20">Португалия</option>
<option value="Великобритания%20">Великобритания</option>
<option value="Швеция%20">Швеция</option>
<option value="Швейцария%20">Швейцария</option>
<option value="Австрия%20">Австрия</option>
<option value="Финляндия%20">Финляндия</option>
<option value="Норвегия%20">Норвегия</option>
<option value="Япония%20">Япония</option>
</select>
</div>
<div class="hidden">
<p>Введите город исходного пункта</p>
<input type="text" id="take-place" name="take-place" data="Украина%20" required />
</div>
<div class="hidden3">
<p>Кooрдинаты:</p>
<p class="resp1"></p>
</div>
<hr>
<div class="select2">
<select id="city2" name="sity2[]">
<option >Ввыберите страну конечного пункта</option>
<option value="Украина%20">Украина</option>
<option value="Россия%20">Россия</option>
<option value="Беларусь%20">Беларусь</option>
<option value="Польша%20">Польша</option>
<option value="Литва%20">Литва</option>
<option value="Латвия%20">Латвия</option>
<option value="Эстония%20">Эстония</option>
<option value="Молдова%20">Молдова</option>
<option value="Словакия%20">Словакия</option>
<option value="Венгрия%20">Венгрия</option>
<option value="Чехия%20">Чехия</option>
<option value="Германия%20">Германия</option>
<option value="Франция%20">Франция</option>
<option value="Словения%20">Словения</option>
<option value="Болгария%20">Болгария</option>
<option value="Италия%20">Италия</option>
<option value="Грузия%20">Грузия</option>
<option value="Казахстан%20">Казахстан</option>
<option value="Армения%20">Армения</option>
<option value="Дания%20">Дания</option>
<option value="Бельгия%20">Бельгия</option>
<option value="Испания%20">Испания</option>
<option value="Португалия%20">Португалия</option>
<option value="Великобритания%20">Великобритания</option>
<option value="Швеция%20">Швеция</option>
<option value="Швейцария%20">Швейцария</option>
<option value="Австрия%20">Австрия</option>
<option value="Финляндия%20">Финляндия</option>
<option value="Норвегия%20">Норвегия</option>
<option value="Япония%20">Япония</option>
</select>
</div>
<div class="hidden2">
<p>Введите город конечного пункта</p>
<input type="text" id="take-place2" name="take-place2" data="Украина%20" required />
</div>
<div class="hidden3">
<p>Кooрдинаты:</p>
<p class="resp2"></p>
</div>
<input id="btn-red" type="button" value="show"/>
<div class="response"></div>
<input type="text" class="step" value="ШАГИ"/>
<div id="navigator">
<input id="btn" type="button" class="before" min="0" value="before"/>
<input type="text" class="step-count" min="0" value="0"/>
<input id="btn" type="button" class="next" min="0" value="next"/>
</div>
<div class="text-step"></div>
</div>
</div>
<div id="map" style="height:0vh;width:100%;"></div>
<div id="map2" style="height:70vh;width:100%;"><img style="max-width:400px;object-fit:cover;display:block;margin-left:auto;margin-right:auto;" src="maps.jpg"/></div>
<script>
var coun =0;
var k1,k2,steps;
$('#city1').on('change',function(){
k1 = $('#city1 option:selected').val();
$('.hidden').css('display','block');
});
$('#city2').on('change',function(){
k2 = $('#city2 option:selected').val();
console.log(k2);
$('.hidden2').css('display','block');
});
var YOUR_API_KEY = 'ВСТАВЬТЕ СВОЙ API KEY';
var r,r2,r3,r1,r12,r7778,prav1,prav2,g,g2,now,now2;
var arr=[];
$('#btn-red').on('click',function(){
$('#map2').replaceWith('<div id="map2" style="height:70vh;width:100%;"></div>');
$('.hidden3').css('display','block');
$('.step').css('display','block');
$('#navigator').css('display','flex');
g = $('#take-place').val();
g2 = $('#take-place2').val();
if(g == '' || g2 == ''){
$('.response').html('<p style="color:red;fon-size:18px;font-weight:bold;">Вы не выбради город!</p>');
setTimeout(function(){ window.location.reload(); }, 3000);
return;
}
now = g+','+k1;
now2 = g2+','+k2 ;
$.ajax({
type: 'get',
url: `https://api.openrouteservice.org/geocode/search?api_key=${YOUR_API_KEY}&text=${now}`,
dataType: 'json',
}).done(function (response) {
r = JSON.stringify(response.features[0].geometry.coordinates);
$('.resp1').html(r);
r1=response.features[0].geometry.coordinates;
prav1=[r1[1],r1[0]];
comon1();
});
});
function comon1(){
$.ajax({
type: 'get',
url: `https://api.openrouteservice.org/geocode/search?api_key=${YOUR_API_KEY}&text=${now2}`,
dataType: 'json',
}).done(function (response) {
r2 = JSON.stringify(response.features[0].geometry.coordinates);
$('.resp2').html(r2);
r12=response.features[0].geometry.coordinates;
prav2=[r12[1],r12[0]];
comon2();
});
}
function comon2(){
$.ajax({
type: 'get',
url: `https://api.openrouteservice.org/v2/directions/driving-car?api_key=${YOUR_API_KEY}&start=${r1}&end=${r12}`,
dataType: 'json',
error:function(response){
var r = JSON.stringify(response.responseJSON.error)
$('.response').html('<p style="color:red;fon-size:18px;font-weight:bold;">'+r+'</p>');
}
}).done(function (response) {
r3 = JSON.stringify(response.features[0].geometry.coordinates);
steps = response.features[0].properties.segments[0].steps;
r7778=response.features[0].geometry.coordinates;
for(var i=0;i<r7778.length; i++){
arr.push([r7778[i][1],r7778[i][0]]);
}
var dist = (response.features[0].properties.summary.distance/1000).toFixed(3);
var d = response.features[0].properties.summary.duration;
var h = Math.floor(d / 3600);
var m = Math.floor(d % 3600 / 60);
var s = Math.floor(d % 3600 % 60);
var hDisplay = h > 0 ? h + (h == 1 ? " час, " : " ч., ") : "";
var mDisplay = m > 0 ? m + (m == 1 ? " минута, " : " мин., ") : "";
var sDisplay = s > 0 ? s + (s == 1 ? " секунда" : " сек.") : "";
$('.response').html('<p>'+dist+' км</p>');
$('.response').append('<p>В пути: '+hDisplay+' '+mDisplay+' '+sDisplay+'</p>');
comon3();
});
}
function comon3(){
var center = prav1;
var end = prav2;
var latlngs =arr;
// Создаём карту
var map2 = L.map('map2').setView(center, 17);
// Настраиваем OSM
L.tileLayer(
'https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18
}).addTo(map2);
var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map2);
// zoom the map to the polyline
map2.fitBounds(polyline.getBounds());
// добавляем маркер в указанном месте
L.marker(center).addTo(map2);
L.marker(end).addTo(map2);
comon4();
}
function comon4(){
$('.step-count').attr('max',steps.length);
$('.step').attr('value','ШАГОВ: '+steps.length);
jQuery(function($){
$('body').on('click','#btn',function(){
if($(this).hasClass('before')){coun--};
if($(this).hasClass('next')){coun++};
if(coun <0){coun=0};
if(coun >steps.length){coun=steps.length-1};
$('.step-count').attr('value',coun);
$('#map').replaceWith('<div id="map" style="height:50vh;width:100%;"></div>');
var count = $('.step-count').val();
current = steps[count];
$('.text-step').html('<p style="color:grey;font-style:italic;max-width:300px;">'+current.instruction+'<br>Дистанция: '+((current.distance)/1000).toFixed(2)+' км<br>Время пути: '+((current.duration)/60).toFixed(0)+'мин, '+((current.duration)%60).toFixed(0)+' сек.</p>');
var N_start = current.way_points[0];
var N_end = current.way_points[1];
var latlngs1 =arr[N_start];
var latlngs2 = arr[N_end];
var arr2=[];
for(var i=N_start; i <=N_end;i++){
arr2.push(arr[i]);
}
var map = L.map('map').setView(latlngs1, 17);
// Настраиваем OSM
L.tileLayer(
'https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
Zoom: 10
}).addTo(map);
var polyline = L.polyline(arr2, {color: 'red'}).addTo(map);
// zoom the map to the polyline
map.fitBounds(polyline.getBounds());
// добавляем маркер в указанном месте
L.marker(latlngs1,{color: 'red'}).addTo(map);
L.marker(latlngs2).addTo(map);
});
});
}
</script>
</body>
</html> Читайте больше по теме: