Создайте службу поиска близлежащих предприятий с помощью платформы Google Maps (JavaScript)

1. Прежде чем начать

Научитесь использовать API Карт и Местоположений платформы Google Карт для создания локального поиска компаний, который определяет местоположение пользователя и показывает интересные места поблизости. Приложение интегрирует геолокацию, информацию о местах, фотографии мест и многое другое.

Предпосылки

  • Базовые знания HTML, CSS и JavaScript
  • Проект с платежным аккаунтом (если у вас его нет, следуйте инструкциям в следующем шаге).
  • Для выполнения шага включения, описанного ниже, вам необходимо включить Maps JavaScript API и Places API .
  • API-ключ для проекта, указанного выше.

Начните работу с платформой Google Карт

Если вы ранее не использовали платформу Google Карт, следуйте руководству «Начало работы с платформой Google Карт» или посмотрите плейлист «Начало работы с платформой Google Карт», чтобы выполнить следующие шаги:

  1. Создайте платежный аккаунт.
  2. Создать проект.
  3. Включите API и SDK платформы Google Карт (перечислены в предыдущем разделе).
  4. Сгенерируйте ключ API.

Что ты будешь делать?

  • Создайте веб-страницу, отображающую карту Google
  • Центрировать карту по местоположению пользователя
  • Найдите близлежащие места и отобразите результаты в виде кликабельных маркеров.
  • Получить и показать более подробную информацию о каждом месте

ae1caf211daa484d.png

Что вам понадобится

  • Веб-браузер, например Google Chrome (рекомендуется), Firefox, Safari или Internet Explorer
  • Ваш любимый текстовый или кодовый редактор

Получить пример кода

  1. Откройте интерфейс командной строки (терминал в MacOS или командную строку в Windows) и загрузите пример кода с помощью этой команды:
git clone https://github.com/googlecodelabs/google-maps-nearby-search-js/

Если это не поможет, нажмите следующую кнопку, чтобы загрузить весь код для этой лабораторной работы, а затем разархивируйте файл:

Загрузите код

  1. Перейдите в каталог, который вы только что клонировали или загрузили.
cd google-maps-nearby-search-js

Папки stepN содержат желаемое конечное состояние каждого шага этой лабораторной работы. Они приведены для справки. Всю работу по кодированию выполняйте в каталоге work .

2. Создайте карту с центром по умолчанию.

Создание карты Google на вашей веб-странице состоит из трех шагов:

  1. Создать HTML-страницу
  2. Добавить карту
  3. Вставьте свой ключ API

1. Создайте HTML-страницу

Ниже представлена карта, созданная на этом этапе. Центр карты расположен на Сиднейском оперном театре в Сиднее, Австралия. Если пользователь откажется от определения своего местоположения, карта по умолчанию будет использовать это местоположение и по-прежнему будет предоставлять интересные результаты поиска.

569b9781658fec74.png

  1. Перейдите в папку work/ . На протяжении всей оставшейся части работы над кодом вносите изменения в версию из папки work/ .
cd work
  1. В каталоге work/ с помощью текстового редактора создайте пустой файл с именем index.html .
  2. Скопируйте следующий код в index.html .

index.html

<!DOCTYPE html>
<html>

<head>
  <title>Sushi Finder</title>
  <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
  <meta charset="utf-8">
  <style>
    /* Always set the map height explicitly to define the size of the div
     * element that contains the map. */
    #map {
      height: 100%;
      background-color: grey;
    }

    /* Optional: Makes the sample page fill the window. */
    html,
    body {
      height: 100%;
      margin: 0;
      padding: 0;
    }

    /* TODO: Step 4A1: Make a generic sidebar. */
  </style>
</head>

<body>
  <!-- TODO: Step 4A2: Add a generic sidebar -->

  <!-- Map appears here -->
  <div id="map"></div>

  <!-- TODO: Step 1B, Add a map -->
</body>

</html>
  1. Откройте файл index.html в вашем веб-браузере.
open index.html

2. Добавить карту

В этом разделе показано, как загрузить API JavaScript Карт на вашу веб-страницу и написать собственный код JavaScript, который использует API для добавления карты на веб-страницу.

  1. Добавьте этот код скрипта туда, где вы видите <!-- TODO: Step 1B, Add a map --> после div map и перед закрывающим тегом </body> .

step1/index.html

<!-- TODO: Step 1B, Add a map -->
<script>
    /* Note: This example requires that you consent to location sharing when
     * prompted by your browser. If you see the error "Geolocation permission
     * denied.", it means you probably did not give permission for the browser * to locate you. */

    /* TODO: Step 2, Geolocate your user
     * Replace the code from here to the END TODO comment with new code from
     * codelab instructions. */
    let pos;
    let map;
    function initMap() {
        // Set the default location and initialize all variables
        pos = {lat: -33.857, lng: 151.213};
        map = new google.maps.Map(document.getElementById('map'), {
            center: pos,
            zoom: 15
        });
    }
    /* END TODO: Step 2, Geolocate your user */
</script>

<!-- TODO: Step 1C, Get an API key -->
<!-- TODO: Step 3A, Load the Places Library -->
<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
</script>

3. Вставьте свой ключ API.

  1. В строке после <!-- TODO: Step 1C, Get an API key --> скопируйте и замените значение параметра key в исходном URL-адресе скрипта на ключ API, созданный вами во время выполнения предварительных требований.

step1/index.html

<!-- TODO: Step 1C, Get an API key -->
<!-- TODO: Step 3A, Load the Places Library -->
<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
</script>
  1. Сохраните HTML-файл, над которым вы работали.

Проверьте это

Перезагрузите в браузере файл, который вы редактировали. На месте серого прямоугольника должна появиться карта. Если вместо неё вы видите сообщение об ошибке, убедитесь, что вы заменили « YOUR_API_KEY » в последнем теге <script> на свой ключ API. См. выше, как получить ключ API, если у вас его ещё нет.

Полный пример кода

Полный код этого проекта на данный момент доступен на Github .

3. Геолокация пользователя

Далее вам необходимо отобразить географическое местоположение пользователя или устройства на карте Google, используя функцию геолокации HTML5 вашего браузера вместе с API Карт JavaScript.

Вот пример карты, которая отображает ваше географическое местоположение, если вы просматриваете страницу из Маунтин-Вью, Калифорния:

1dbb3fec117cd895.png

Что такое геолокация?

Геолокация — это определение географического местоположения пользователя или вычислительного устройства посредством различных механизмов сбора данных. Как правило, большинство геолокационных сервисов используют адреса сетевой маршрутизации или внутренние GPS-устройства для определения местоположения. Данное приложение использует свойство веб-браузера navigator.geolocation соответствующее стандарту геолокации W3C, для определения местоположения пользователя.

Попробуйте сами.

Замените код между комментариями TODO: Step 2, Geolocate your user и END TODO: Step 2, Geolocate your user следующим кодом:

step2/index.html

/* TODO: Step 2, Geolocate your user
    * Replace the code from here to the END TODO comment with this code
    * from codelab instructions. */
let pos;
let map;
let bounds;
let infoWindow;
let currentInfoWindow;
let service;
let infoPane;
function initMap() {
    // Initialize variables
    bounds = new google.maps.LatLngBounds();
    infoWindow = new google.maps.InfoWindow;
    currentInfoWindow = infoWindow;
    /* TODO: Step 4A3: Add a generic sidebar */

    // Try HTML5 geolocation
    if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(position => {
        pos = {
        lat: position.coords.latitude,
        lng: position.coords.longitude
        };
        map = new google.maps.Map(document.getElementById('map'), {
        center: pos,
        zoom: 15
        });
        bounds.extend(pos);

        infoWindow.setPosition(pos);
        infoWindow.setContent('Location found.');
        infoWindow.open(map);
        map.setCenter(pos);

        /* TODO: Step 3B2, Call the Places Nearby Search */
    }, () => {
        // Browser supports geolocation, but user has denied permission
        handleLocationError(true, infoWindow);
    });
    } else {
    // Browser doesn't support geolocation
    handleLocationError(false, infoWindow);
    }
}

// Handle a geolocation error
function handleLocationError(browserHasGeolocation, infoWindow) {
    // Set default location to Sydney, Australia
    pos = {lat: -33.856, lng: 151.215};
    map = new google.maps.Map(document.getElementById('map'), {
    center: pos,
    zoom: 15
    });

    // Display an InfoWindow at the map center
    infoWindow.setPosition(pos);
    infoWindow.setContent(browserHasGeolocation ?
    'Geolocation permissions denied. Using default location.' :
    'Error: Your browser doesn\'t support geolocation.');
    infoWindow.open(map);
    currentInfoWindow = infoWindow;

    /* TODO: Step 3B3, Call the Places Nearby Search */
}
/* END TODO: Step 2, Geolocate your user */
/* TODO: Step 3B1, Call the Places Nearby Search */

Проверьте это

  1. Сохраните файл.
  2. Перезагрузите страницу.

Теперь ваш браузер должен запросить разрешение на передачу вашего местоположения приложению.

  1. Нажмите кнопку «Заблокировать» один раз, чтобы увидеть, корректно ли система обработает ошибку и останется ли она центрированной на Сиднее.
  2. Перезагрузите страницу еще раз и нажмите « Разрешить» , чтобы проверить, работает ли геолокация и перемещает ли карта в ваше текущее местоположение.

Полный пример кода

Полный код этого проекта на данный момент доступен на Github .

4. Поиск мест поблизости

Поиск поблизости позволяет искать места в указанной области по ключевому слову или типу. Поиск поблизости всегда должен включать местоположение, которое можно указать одним из двух способов:

  • Объект LatLngBounds , определяющий прямоугольную область поиска.
  • Круговая область, определяемая как комбинация свойства location (указывающего центр круга как объект LatLng ) и радиуса, измеряемого в метрах.

Инициируйте поиск поблизости, вызвав метод PlacesService nearbySearch() , который вернет массив объектов PlaceResult .

А. Загрузить библиотеку мест

Во-первых, чтобы получить доступ к службам библиотеки Places, обновите URL-адрес источника скрипта, введя параметр libraries и добавив places в качестве значения.

step3/index.html

<!-- TODO: Step 3A, Load the Places Library -->
<script async defer
    src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initMap">

B. Вызовите запрос поиска мест поблизости и обработайте ответ.

Затем сформируйте запрос PlaceSearch. Минимальный набор обязательных полей:

Минимально необходимые поля:

  • bounds , который должен быть объектом google.maps.LatLngBounds , определяющим прямоугольную область поиска, или location и radius ; первый принимает объект google.maps.LatLng , а второй — простое целое число, представляющее радиус круга в метрах. Максимально допустимый радиус составляет 50 000 метров. Обратите внимание, что если rankBy установлен в DISTANCE , необходимо указать местоположение, но нельзя указать радиус или границы.
  • keyword , которое будет сопоставляться со всеми доступными полями, включая, помимо прочего, имя, тип и адрес, а также отзывы клиентов и другой сторонний контент, или type , ограничивающий результаты местами, соответствующими указанному типу. Можно указать только один тип (если указано несколько типов, все типы, следующие за первым, игнорируются). См. список поддерживаемых типов .

В этой лабораторной работе вы будете использовать текущее местоположение пользователя в качестве местоположения для поиска и ранжировать результаты по расстоянию.

  1. Добавьте следующее в комментарий TODO: Step 3B1 , чтобы написать две функции для вызова поиска и обработки ответа.

В качестве поискового запроса используется ключевое слово sushi , но вы можете изменить его. Код для определения функции createMarkers приведён в следующем разделе.

step3/index.html

/* TODO: Step 3B1, Call the Places Nearby Search */
// Perform a Places Nearby Search Request
function getNearbyPlaces(position) {
    let request = {
    location: position,
    rankBy: google.maps.places.RankBy.DISTANCE,
    keyword: 'sushi'
    };

    service = new google.maps.places.PlacesService(map);
    service.nearbySearch(request, nearbyCallback);
}

// Handle the results (up to 20) of the Nearby Search
function nearbyCallback(results, status) {
    if (status == google.maps.places.PlacesServiceStatus.OK) {
    createMarkers(results);
    }
}

/* TODO: Step 3C, Generate markers for search results */
  1. Добавьте эту строку в конец функции initMap в комментарии TODO: Step 3B2 .
/* TODO: Step 3B2, Call the Places Nearby Search */
// Call Places Nearby Search on user's location
getNearbyPlaces(pos);
  1. Добавьте эту строку в конец функции handleLocationError в комментарии TODO: Step 3B3 .
/* TODO: Step 3B3, Call the Places Nearby Search */
// Call Places Nearby Search on the default location
getNearbyPlaces(pos);

C. Генерация маркеров для результатов поиска

Маркер обозначает местоположение на карте. По умолчанию маркер использует стандартное изображение. Информация о настройке изображений маркеров представлена в разделе «Маркеры» .

Конструктор google.maps.Marker принимает один литерал объекта Marker options , определяющий начальные свойства маркера.

Следующие поля особенно важны и обычно задаются при построении маркера:

  • position (обязательно) указывает LatLng , определяющий начальное местоположение маркера.
  • map (необязательно) определяет карту, на которой будет размещен маркер. Если карта не указана при создании маркера, маркер будет создан, но не будет прикреплён к карте (или отображен на ней). Вы можете добавить маркер позже, вызвав метод setMap() маркера.
  • Добавьте следующий код после комментария TODO: Step 3C , чтобы задать положение, карту и название для одного маркера для каждого места, возвращаемого в ответе. Также используйте метод extend переменной bounds , чтобы обеспечить видимость центра и всех маркеров на карте.

step3/index.html

/* TODO: Step 3C, Generate markers for search results */
// Set markers at the location of each place result
function createMarkers(places) {
    places.forEach(place => {
    let marker = new google.maps.Marker({
        position: place.geometry.location,
        map: map,
        title: place.name
    });

    /* TODO: Step 4B: Add click listeners to the markers */

    // Adjust the map bounds to include the location of this marker
    bounds.extend(place.geometry.location);
    });
    /* Once all the markers have been placed, adjust the bounds of the map to
    * show all the markers within the visible area. */
    map.fitBounds(bounds);
}

/* TODO: Step 4C: Show place details in an info window */

Проверьте это

  1. Сохраните и перезагрузите страницу, а затем нажмите «Разрешить» , чтобы предоставить разрешения на геолокацию.

Вокруг центра карты вы увидите до 20 красных маркеров.

  1. Перезагрузите страницу еще раз и на этот раз заблокируйте разрешения на геолокацию.

Вы по-прежнему получаете результаты в центре вашей карты по умолчанию (в примере центром по умолчанию является Сидней, Австралия)?

Полный пример кода

Полный код этого проекта на данный момент доступен на Github .

5. Показывать информацию о месте по запросу

Получив идентификатор места (который отображается в качестве одного из полей в результатах поиска поблизости), вы можете запросить дополнительную информацию о нём, например, полный адрес, номер телефона, а также оценки и отзывы пользователей. В этой лабораторной работе вы создадите боковую панель для отображения подробной информации о месте и сделаете маркеры интерактивными, чтобы пользователь мог выбирать места для просмотра подробной информации.

А. Создайте общую боковую панель

Вам нужно место для отображения сведений о месте, поэтому вот простой код для боковой панели, которую можно использовать для выдвижения и отображения сведений о месте, когда пользователь нажимает на маркер.

  1. Добавьте следующий код в тег style после комментария TODO: Step 4A1 :

step4/index.html

/* TODO: Step 4A1: Make a generic sidebar */
/* Styling for an info pane that slides out from the left. 
    * Hidden by default. */
#panel {
    height: 100%;
    width: null;
    background-color: white;
    position: fixed;
    z-index: 1;
    overflow-x: hidden;
    transition: all .2s ease-out;
}

.open {
    width: 250px;
}

/* Styling for place details */
.hero {
    width: 100%;
    height: auto;
    max-height: 166px;
    display: block;
}

.place,
p {
    font-family: 'open sans', arial, sans-serif;
    padding-left: 18px;
    padding-right: 18px;
}

.details {
    color: darkslategrey;
}

a {
    text-decoration: none;
    color: cadetblue;
}
  1. В разделе body непосредственно перед блоком div map добавьте блок div для панели подробностей.
<!-- TODO: Step 4A2: Add a generic sidebar -->
<!-- The slide-out panel for showing place details -->
<div id="panel"></div>
  1. В функции initMap() после комментария TODO: Step 4A3 инициализируйте переменную infoPane следующим образом:
/* TODO: Step 4A3: Add a generic sidebar */
infoPane = document.getElementById('panel');

Б. Добавьте прослушиватели щелчков к маркерам

  1. В функции createMarkers добавьте прослушиватель щелчков для каждого маркера по мере их создания.

Прослушиватель щелчков извлекает сведения о месте, связанном с этим маркером, и вызывает функцию для отображения сведений.

  1. Вставьте следующий код в функцию createMarkers в комментарий к коду TODO: Step 4B .

Метод showDetails реализован в следующем разделе.

step4/index.html

/* TODO: Step 4B: Add click listeners to the markers */
// Add click listener to each marker
google.maps.event.addListener(marker, 'click', () => {
    let request = {
    placeId: place.place_id,
    fields: ['name', 'formatted_address', 'geometry', 'rating',
        'website', 'photos']
    };

    /* Only fetch the details of a place when the user clicks on a marker.
    * If we fetch the details for all place results as soon as we get
    * the search response, we will hit API rate limits. */
    service.getDetails(request, (placeResult, status) => {
    showDetails(placeResult, marker, status)
    });
});

В запросе addListener свойство placeId указывает одно место для запроса сведений, а свойство fields представляет собой массив имён полей с информацией, которую нужно вернуть об этом месте. Полный список полей, которые можно запросить, см. в разделе Интерфейс PlaceResult .

C. Показать сведения о месте в информационном окне

Информационное окно отображает содержимое (обычно текст или изображения) в диалоговом окне над заданным местом на карте. Информационное окно состоит из области содержимого и конической ножки. Кончик ножки прикреплён к указанному месту на карте. Обычно информационные окна прикрепляются к маркерам, но вы также можете прикрепить информационное окно к определённой широте/долготе.

  1. Добавьте следующий код в комментарий TODO: Step 4C , чтобы создать InfoWindow , отображающее название и рейтинг компании, и прикрепить это окно к маркеру.

В следующем разделе вы определяете showPanel для отображения подробностей на боковой панели.

step4/index.html

/* TODO: Step 4C: Show place details in an info window */
// Builds an InfoWindow to display details above the marker
function showDetails(placeResult, marker, status) {
    if (status == google.maps.places.PlacesServiceStatus.OK) {
    let placeInfowindow = new google.maps.InfoWindow();
    placeInfowindow.setContent('<div><strong>' + placeResult.name +
        '</strong><br>' + 'Rating: ' + placeResult.rating + '</div>');
    placeInfowindow.open(marker.map, marker);
    currentInfoWindow.close();
    currentInfoWindow = placeInfowindow;
    showPanel(placeResult);
    } else {
    console.log('showDetails failed: ' + status);
    }
}

/* TODO: Step 4D: Load place details in a sidebar */

D. Загрузить информацию о месте на боковой панели

Используйте те же данные, возвращаемые объектом PlaceResult , для заполнения другого элемента div. В этом примере используется infoPane — произвольное имя переменной для элемента div с идентификатором « panel ». Каждый раз, когда пользователь нажимает на новый маркер, этот код закрывает боковую панель, если она уже открыта, стирает старые данные, добавляет новые и открывает боковую панель.

  1. Добавьте следующий код после комментария TODO: Step 4D .

step4/index.html

/* TODO: Step 4D: Load place details in a sidebar */
// Displays place details in a sidebar
function showPanel(placeResult) {
    // If infoPane is already open, close it
    if (infoPane.classList.contains("open")) {
    infoPane.classList.remove("open");
    }

    // Clear the previous details
    while (infoPane.lastChild) {
    infoPane.removeChild(infoPane.lastChild);
    }

    /* TODO: Step 4E: Display a Place Photo with the Place Details */

    // Add place details with text formatting
    let name = document.createElement('h1');
    name.classList.add('place');
    name.textContent = placeResult.name;
    infoPane.appendChild(name);
    if (placeResult.rating != null) {
    let rating = document.createElement('p');
    rating.classList.add('details');
    rating.textContent = `Rating: ${placeResult.rating} \u272e`;
    infoPane.appendChild(rating);
    }
    let address = document.createElement('p');
    address.classList.add('details');
    address.textContent = placeResult.formatted_address;
    infoPane.appendChild(address);
    if (placeResult.website) {
    let websitePara = document.createElement('p');
    let websiteLink = document.createElement('a');
    let websiteUrl = document.createTextNode(placeResult.website);
    websiteLink.appendChild(websiteUrl);
    websiteLink.title = placeResult.website;
    websiteLink.href = placeResult.website;
    websitePara.appendChild(websiteLink);
    infoPane.appendChild(websitePara);
    }

    // Open the infoPane
    infoPane.classList.add("open");
}

E. Отображение фотографии места с информацией о нем

Результат getDetails возвращает массив, содержащий до 10 фотографий, связанных с placeId . Здесь первая фотография отображается над названием места в боковой панели.

  1. Поместите этот код перед созданием элемента name , если вы хотите, чтобы фотография отображалась в верхней части боковой панели.

step4/index.html

/* TODO: Step 4E: Display a Place Photo with the Place Details */
// Add the primary photo, if there is one
if (placeResult.photos != null) {
    let firstPhoto = placeResult.photos[0];
    let photo = document.createElement('img');
    photo.classList.add('hero');
    photo.src = firstPhoto.getUrl();
    infoPane.appendChild(photo);
}

Проверьте это

  1. Сохраните и перезагрузите страницу в браузере и разрешите доступ к геолокации.
  2. Щелкните по маркеру, чтобы увидеть всплывающее информационное окно с некоторыми подробностями, а также выдвижную боковую панель слева для отображения дополнительных сведений.
  3. Проверьте, работает ли поиск, если вы перезагрузите страницу и отмените доступ к геолокации. Измените ключевое слово поиска на другой запрос и изучите результаты.

ae1caf211daa484d.png

Полный пример кода

Полный код этого проекта на данный момент доступен на Github .

6. Поздравления

Поздравляем! Вы использовали множество функций Maps JavaScript API, включая библиотеку Places .

Что мы рассмотрели

Узнать больше

Чтобы использовать карты ещё эффективнее, изучите документацию Maps JavaScript API и документацию Places Library . Обе эти книги содержат руководства, учебные материалы, справочник по API, дополнительные примеры кода и каналы поддержки. Среди популярных функций — импорт данных в карты , настройка стиля карты и добавление сервиса Street View .

Какую следующую лабораторную работу вы бы хотели, чтобы мы создали?

Больше примеров использования расширенной информации о местах Больше практических работ с использованием JavaScript API платформы Карт Больше кодлабов для Android Больше кодлабов для iOS Визуализация данных о местоположении на картах Индивидуальный стиль карт Использование StreetView

Нужная вам кодлаб-программа не указана выше? Запросите её в новом выпуске здесь .