Планувальник подорожей своїми руками за пару годин


Автор: Сергій Матвєєнко

Одного разу до мене прийшов інвестор одного проекту і сказав: «Давай зробимо планувальник подорожей по картах Google!» Я погодився. Тоді інвестор став розповідати, як техдиректор уявляв собі архітектуру цього планувальника: він говорив щось про зв'язок з сервером, про ключ API, про запити в Google, про гроші за запити, яких буде багато і т. д. Все виглядало складно і красиво. Однак потім ми почали уважно читати документацію Google API і раптом зрозуміли, що насправді нам сервер не потрібен. Взагалі! Весь планувальник можна зробити на клієнті. А найцікавіше — ми можемо обійтися навіть без API-ключа (за умови, що ми будемо використовувати JS API). У підсумку я за два дні зміг написати такий планувальник, з логікою на стороні клієнта, на основі Google API, без використання сервера. Все виявилося дуже просто.

Я розповім, як можна зробити найпростіший планувальник такого роду буквально за пару годин. Звичайно, за цей час можна зібрати тільки прототип, але головне — він буде працювати! Його головною функцією буде прокладання оптимального маршруту між пам'ятками в який нас цікавить, місті; може бути розбивка плану поїздки по днях. Все буде зроблено на AngularJS з використанням Google Maps/Places API. Я розповім про особливості роботи з цим API і про деяких можливостях, які не вказані в документації. Також ми поговоримо про виділення логіки в клієнтські додатки.

Отже, як саме буде виглядати такий планувальник? Це буде просто рядок пошуку в браузері, в яку ми будемо вводити назву нас цікавить міста або місця. У відповідь на такий запит нам видаватиметься це місце на карті Google, список пам'яток в цьому місці і найближчих околицях з описом, фотографіями та відгуками. І, звичайно, між пам'ятками буде прокладати оптимальний маршрут по картах Google c зазначенням приблизного часу переміщення між ними. Також можна буде легко додати можливість розбити план відвідин пам'яток по днях.

Що нам знадобиться?

По-перше, нам знадобиться бібліотека GooglePlaces. Це найголовніше, що забезпечить роботу планувальника:

<script src="https://maps.googleapis.com/maps/api/is?libraries=places&language=en"></script>



  Autocomplete, дуже корисний проект для AngularJS, який обертає бібліотеку Google Places і роботу з автозаповненням. Rawgit — обв'язка навколо GitHub, у якої теж є CDN.

<script src="https://rawgit.com/kuhnza/angular-google-places-autocomplete/0.2.7/src/autocomplete.js"></script>


— це власне AngularJS.
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>


  Bootstrap.

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>


  jQuery, який потрібен Bootstrap'у.

<link rel="stylesheet"
href=https://max-cdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet"
href=https://rawgit.com/kuhnza/angular-google-places-autocomplete/master/dist/autocomplete.min.css">


  таблиці стилів від Autocomplete і Bootstrap.

Ось і все зовнішнє, що у нас є. Все це завантажене з CDN — сервер нам не потрібен взагалі!
Шукаємо місце на карті

Тепер спробуємо зробити пошук цікавить нас міста на карті. Ось як ми використовуємо Autocomplete:

<input type="text" class="form-control input-lg"
g-places-autocomplete ng-model="destinationData"
placeholder="Enter destination">
<button ng-click="showDestination = !showDestination"
class="btn btn-block btn-default btn-xs">destinationData</button>
<pre ng-show="showDestination">{{destination|json}} < /pre>
<div id="map" style="height: 200px;"></div>


Як ми бачимо, тут у нас один input:

<input type="text" class="form-control input-lg" 
g-places-autocomplete ng-model="destinationData" 
placeholder="Enter destination">


Таким чином, завдяки Angular-проекту Google Places Autocomplete ми отримуємо працює автозаповнення. Це означає, що ми можемо почати вводити назву місця у форму пошуку (навіть з помилками), і нам в пошуку будуть пропонуватися підходящі варіанти:


У результаті у нас вийшов пошук місця з відображенням його місцеположення на карті Google:



Що далі?

Шукаємо найближчі визначні пам'ятки

Раніше (до версії 3) пошук по місцях в Google API здійснювався одним методом — там було дуже багато параметрів, і все було дуже складно. Тепер пошук поділений на три методу. Зокрема, з'явився виділений radar search — пошук по найближчих цікавим місцям. Раніше такі місця доводилося додатково фільтрувати, т. к. в результатах пошуку траплялися міста і країни. А зараз все просто.

Як він працює?

Google пропонує зазвичай відразу показувати результати пошуку на карті. Але, насправді, нам це зараз не потрібно, адже ми просто хочемо отримати список найближчих місць. Тому ми використовуємо radar search (
service.radarSearch
) без карти в радіусі 50 км — це звичайний радіус міста і околиць. Ми шукаємо звичайні туристичні місця зразок музеїв, церков, нічних клубів, зоопарків і т. д., які ми перераховуємо як типи Google (
types
).

$scope.destinationOptions = {
location : destination.geometry.location,
radius : 50000
};
$scope.popularPoints = [];
$scope.map = new google.maps.Map(document.getElementById('map'), {
center : $scope.destinationOptions.location,
zoom : 5
});
var service = new google.maps.places.PlacesService($scope.map);
var radarOptions = {
location : $scope.destinationOptions.location,
radius : $scope.destinationOptions.radius,
types : [ 'airport', 'amusement_park', 'aquarium', 'art_gallery', 'casino', 'church',
'city_hall', 'courthouse', 'hindu_temple', 'library', 'museum', 'night_club',
'park', 'stadium', 'synagogue', 'university', 'zoo' ]
};
service.radarSearch(radarOptions, function(points) {
points.slice(0, 8).forEach(function(point) {
service.getDetails({
placeId : point.place_id
}, function(details) {
$scope.popularPoints.push(details);
});
});
$scope.$digest();
});


Отже, ми отримуємо запит до радар-пошуку і замість того, щоб використовувати рендерер і почати працювати з картою, забираємо все Angular, і пошук видає нам вісім перших місць (а він повертає 200 результатів). Відразу ж ми з допомогою того ж сервісу запитуємо подробиці про місцях і додаємо до себе в ангуляровский scope:
$scope.popularPoints.push(details)
.



Так ми зробили пошук — коли знаходимо місце на карті, тут же відображається список усіх визначних місць в радіусі 50 км. Також, якщо це потрібно, ми зможемо розкрити цей список і побачити зображення цього місця, а також різні подробиці та коментарі користувачів з рейтингом.



Прокладаємо маршрут

Але якщо б я просто показав найкращі пам'ятки в результатах пошуку, інвестор був би незадоволений, адже хочеться ще спланувати найкращий маршрут по цих місцях. Тому під результатами пошуку у нас буде кнопка, яка зможе показати нам цей маршрут. Як вона працює?

Виявляється, і тут теж Google все зробив за нас — він надає повний інтерфейс до механізмів Google Maps з планування і прокладання маршрутів — аж до проміжних точок. Але, як люблять говорити деякі мої знайомі, API тут зроблено «чужими для хижаків». Тому що, якщо у мене є список точок, я просто хочу передати їх разом і сказати, що збираюся з ним поїздити. Але виявляється, що так не буває, а буває так, що ми починаємо тільки в якомусь одному місці і закінчуємо в якомусь іншому конкретному місці, і всередині потрібно вицепіть slice'ом проміжні точки.

$scope.tripCalc = function() {
var directionsService = new google.maps.DirectionsService();
directionsService.route({
origin : $scope.points[0].geometry.location,
destination : $scope.points[$scope.points.length - 1].geometry.location,
waypoints : $scope.points.slice(1, $scope.points.length - 1).map(function(point) {
return {
location : point.geometry.location
};
}),
travelMode: google.maps.TravelMode.DRIVING
}, function(result) {
$scope.route = result;
$scope.$digest();
});
}


Однак ми знайшли вихід — замикали точки початку (
origin
) і кінця (
destination
) маршруту готель, в якому відпочиває людина. Також ми потім зробили і розбивки по днях — з урахуванням, що ночувати ми можемо в різних готелях. Т.ч. можна зробити і так, наприклад, що початкова точка — аеропорт, друга — пункт оренди автомобілів, а кінцева — готель першої ночі. Ще ми можемо прокласти маршрут так, щоб шукати в середині дня ресторани, щоб пообідати. Всі ці точки можна отримати за допомогою вказівки відповідних типів у запиті до API Google Maps (параметр
types
). Насправді, це просте завдання програмування — вибудувати масив об'єктів і відобразити його в
waypoints
. Так ми отримуємо готовий маршрут.

Найцікавіше і найприємніше — можливість показувати дистанцію і час, який буде витрачено на те, щоб переміститися між двома точками маршруту. Це означає, що, якщо ми, наприклад, їдемо між точками шість годин — це підказка, щоб підшукати ресторан по дорозі, а якщо їдемо через ніч — отже, добре б підказати і готель. Все це робиться на клієнта.

Потрібен сервер?

І тут ми підходимо до цікавої дискусії, яка виникла у нас, коли ми робили цей планувальник подорожей. А чи справді ми хочемо зберігати все це на сервері? Чи потрібно нам знати, що шукав користувач?

Насправді, нам цікаво тільки одне: щоб користувач замовив у нас те, що ми хочемо продати. Не буду говорити, що ми хотіли продати користувачеві, але, припустимо, це можуть бути кімнати в готелях, які він вибрав в цьому планувальнику. За великим рахунком, цей планувальник — просто added value, додана вартість, всього лише зручний сервіс на сайті, який продає кімнати у готелях. Т. ч. нам на сервері зберігати нічого не потрібно — все можна робити на клієнті. Таким чином, ми можемо просто прикрутити кнопки для бронювання номерів в готелях там, де ці готелі відображаються при плануванні маршруту.

Звичайно, якась аналітика нам все ж може знадобитися, але і тут ми можемо обійтися без сервера, якщо використовуємо Google Analytics. Так, наприклад, якщо нам потрібно знати, які місця найбільше шукали користувачі, текст пошуку може без проблем стрибати через HTML5 API в URL, і Google Analytics це підхопить.

Все інше нас вже не дуже хвилює. Ми можемо тепер рекламувати сторінку, а Google нехай справляється з навантаженням — при цьому буде обмежена тільки кількість запитів з одного IP, тобто від користувача. Ми можемо викласти на сторінку Amazon S3 і тоді зможемо взагалі не думати про навантаження і про те, що наша рекламна кампанія може покласти наші сервери. Якщо ж ми додамо ще відгуки від користувачів, користувач почне зав'язуватися на якийсь інтерактив на сайті, який, насправді, весь завантажений зовні.

Так що планувальник ми практично зробили   ще трохи, і його можна продавати.

Насправді, саме такі способи організації інтерфейсу найефективніше. Зараз великі постачальники дійсно зробили все, щоб нам ні про що не треба було турбуватися. Наприклад, останні два роки, коли мої знайомі питали, як їм зробити сайт, я не міг відповісти їм нічого кращого, крім як: «Ідіть на blogspot». Адже там все є! Так і Google Maps надає все, що потрібно. Але на яких умовах?

Умови використання google maps API

Якщо побіжно читати офіційні інструкції до Google Maps API, може здатися, що все обов'язково повинно відбуватися десь на картах Google — ми повинні щось намалювати і нічого з цим не робити. Але, якщо читати уважніше, виявляється, що, за умовами Google, все, що ми зобов'язані робити — це, грубо кажучи, намалювати в нижньому куті логотип Google і посилання на всякі умови використання. Виходить, що Google дав нам всі необхідні дані, і ми на їх основі можемо хоч власну мапу малювати і взагалі розпихати ці дані, як нам завгодно, лише б не забути написати, що дані отримані від Google. Тому ви можете робити на сайті все, що завгодно на JavaScript, і без всякого сервера.

Ісходник проекту
Gist
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.