Собственный сервис поиска с помощью Google Maps

Владимир | | HTML, JavaScript, Web разработка.

google maps screenshot

Современные web сервисы позволяют с минимальными усилиями существенно расширить функциональность сайта.

Сегодня речь пойдет об использовании карт от Google на собственном сайте.

Для начала определимся с задачей.

Допустим, нам нужно сделать поиск по картам. Т.е. посетитель вводит название города в поле формы, нажимает кнопку «Найти».

После этого наше приложение показывает соответствующую карту.

В общем, должно получиться что-то похожее на эту страницу.

Переходим к реализации.

Для использования карт Google на собственном сайте нужно получить специальный ключ (AJAX Search API Key).

Процедура предельно простая. Заходим на страницу регистрации, соглашаемся с лицензией, вводим адрес сайта в форму и жмем кнопку «Generate API Key».

В результате вы получите длинную строку с ключом.

Размещаем карту на странице.

Эта операция выполняется в два шага.

1) Подготавливаем на странице блок для карты

<div id="map_canvas" style="width: 600px; height: 400px"></div>

Здесь нужно только задать его размеры (в данном случае — 600х400 px).

2) В заголовке страницы подключаем Google API и небольшой скрипт, который и создает карту

<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;key=ваш_ключ"
        type="text/javascript"></script>
<script type="text/javascript">

var map;

function initialize() {
	//создаем объект для работы с картой
	map = new GMap2(document.getElementById("map_canvas"));
	if (GBrowserIsCompatible()) {
		//устанавливаем координаты и начальное приближение
		map.setCenter(new GLatLng(50.453629, 30.502838), 13);
		//добавляем шкалу зума
		map.addControl(new GLargeMapControl());
		//добавляем переключатель типа карт (Карта, Спутник, Гибрид)
		map.addControl(new GMapTypeControl());
		//указываем тип карты по-умолчанию (Спутник)
		map.setMapType(G_SATELLITE_MAP);
	}
}
</script>

Этот скрипт создает объект типа GMap2 и связывает его с блоком, в котором должна быть размещена карта (map_canvas).

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

Метод setCenter указывает какая точка на должна находится в центре карты и величину приближения (зума). В этом примере я указал координаты Киева. Подробнее на них мы остановимся чуть позже.

Метод addControl добавляет на карту различные элементы управления. В данном случае мы добавили блок навигации и зума (GLargeMapControl) и переключатель типа карт (GMapTypeControl).

И, наконец, устанавливаем тип карты, которая используется по-умолчанию (G_SATELLITE_MAP – спутниковая карта).

Добавляем форму поиска

<label for="sityname">Название города: </label>
<input type="text" name="sityname" id="sityname" />
<input type="button" onclick="getAdress()" value="Найти" />

Тут все предельно просто. Поле для ввода адреса и кнопка «Найти».

Теперь немного теории.

Преобразования адреса в географические координаты называется геокодингом (Geocoding). В Google Maps для эту операцию выполняет специальный объект GClientGeocoder.

Т.е. нам нужно выполнить такие операции.

1) Создать объект GclientGeocoder.

2) С помощью его метода getLatLng определить координаты.

3) Установить на карте маркер в полученной точке.

4) Добавить на карту надпись.

Все описанные операции выполняются двумя небольшими функциями.

var geocoder = new GClientGeocoder();

function getAdress() {
	var address = document.getElementById("sityname").value;
	geocoder.getLatLng(
		address,
		function(point) {
			if (!point) {
				alert(address + " не найден");
			} else {
				geocoder.getLocations(address, addAdr);
			}
		}
	);
}

function addAdr(response) {
	//удаляем слои, если они есть
	map.clearOverlays();
	if (!response || response.Status.code != 200) {
		alert("\"" + address + "\" не найден");
	} else {
		//создаем объект типа GLatLng и надпись
		place = response.Placemark[0];
		point = new GLatLng(place.Point.coordinates[1],
					place.Point.coordinates[0]);
		marker = new GMarker(point);
		//размещаем надпись на карте
		map.addOverlay(marker);
		//добавляем текст на надпись
		marker.openInfoWindowHtml(place.address + '<br />' + 
			'Широта: ' + place.Point.coordinates[1] + '<br />' +
			'Долгота: ' + place.Point.coordinates[0]);
	}
}

При нажатии на кнопку «Найти» вызывается функция getAdress, которая вызывает метод getLatLng. В его первом параметре передается введенный пользователем адрес, а во втором объявлена анонимная функция, которая будет вызвана полсе получения результатов обработки адреса.

Эта функция в качестве параметра получает точку с координатами. В принципе, этого достаточно, чтобы показать нужную карту, но мы можем получить более подробную информацию с помощью метода getLocations.

Этот метод также как и getLatLng в первом параметре получает адрес, а во втором – имя функции, которая будет вызвана после получения данных. В данном примере это addAdr.

Функция addAdr получает результат выполнения метода getLocations, т.е. структуру с данными. После мы просто устанавливаем на карте маркер (метод addOverlay объекта GMap2) и надпись с текстом (метод openInfoWindowHtml).

Заключение

В этом примере показаны далеко не все возможности Google Maps. API довольно большой и постоянно развивается.

Главная проблема в том, что далеко не для всех городов СНГ существуют обычные карты (с названиями улиц). Спутниковые фотографии, конечно, есть, но по ним не всегда удобно ориентироваться. Кстати, именно по этой причине я по-умолчанию установил тип карты G_SATELLITE_MAP.

В этом плане очень привлекательно выглядят карты Яндекса. Например, карта Киева у них есть 🙂 . Но API они открыли совсем недавно и, насколько я знаю, у них были проблемы с кириллицей (будем надеяться, что это быстро исправят).

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

Скачать пример

Вы можете скачать архив с примером, приведенным в этой статье. Для использования вам нужно будет заменить в файле index.html строку your_google_api_key на ваш ключ (API Key).

Или можно просто поиграться с картой 🙂

До встречи!

  • Очень полезно такое использовать на сайте про недвижимость, чтобы на специальной странице посетители могли увидеть дом на карте. Да и других вариантов применения можно найти массу.

    • Тут вопрос спорный. Скорее всего покупатель захочет увидеть фасад дома, а не крышу.

      • Конечно, одним снимком из космоса не обойтись, нужно будет добавлять и другие фотографии. Зато будет видно в каком районе находится дом, в промзоне или более менее чистом.

  • Очень полезно такое использовать на сайте про недвижимость, чтобы на специальной странице посетители могли увидеть дом на карте. Да и других вариантов применения можно найти массу.

    • Тут вопрос спорный. Скорее всего покупатель захочет увидеть фасад дома, а не крышу.

      • Конечно, одним снимком из космоса не обойтись, нужно будет добавлять и другие фотографии. Зато будет видно в каком районе находится дом, в промзоне или более менее чистом.

  • Нучно чтоб покупатель смог оценить весь дом а не по частям, без этого никуда.

    • Пожалуй соглашусь. Лишняя фотография лишней не будет (прошу прощения за тавтологию 🙂 )

  • Нучно чтоб покупатель смог оценить весь дом а не по частям, без этого никуда.

    • Пожалуй соглашусь. Лишняя фотография лишней не будет (прошу прощения за тавтологию 🙂 )

  • интересная тема. кстати, для wordpress есть плагин UMapper с похожей функциональностью

    • Последнее время у меня складывается впечатление, что для WP есть все 🙂

      • Не писал интеграцию с Google Maps. Но со стороны это казалось чем-то магическим и непостижимым. На практике же все оказалось довольно просто.

        Владимир, отличная статья. Пойду попробую написать, что-то подобное.

  • интересная тема. кстати, для wordpress есть плагин UMapper с похожей функциональностью

    • Последнее время у меня складывается впечатление, что для WP есть все 🙂

      • Не писал интеграцию с Google Maps. Но со стороны это казалось чем-то магическим и непостижимым. На практике же все оказалось довольно просто.

        Владимир, отличная статья. Пойду попробую написать, что-то подобное.

  • Очень полезная статья. Пригодилась
    Автору спасибо.
    Попробую у себя такую штуку устроить 🙂

  • Очень полезная статья. Пригодилась
    Автору спасибо.
    Попробую у себя такую штуку устроить 🙂

  • Это гора Эверест! Однозначно!!

  • Это гора Эверест! Однозначно!!

  • Anton

    Вячеслав, не подскажете?
    Можно ли как то получить координаты точки при помощи geocoder, что бы marker добавлять вне function?
    Типа:

    var piont = geocoder.getLatLng(address, function(response){может отсюда можно вернуть значение?})
    marker = new GMarker(point);
    map.addOverlay(marker);

    Не могу разобраться никак… =( Буду очень благодарен за помощь!

    • Проблема в том, что метод getLatLng отправляет асинхронный (ajax) запрос серверу, который может занять некоторое время.
      Т.е. строка marker = new GMarker(point) скорее всего выполнится до того как будет получен ответ.
      Именно по этому во втором параметре указывается функция, которая будет обрабатывать ответ сервера. Она гарантированно начнет выполняться после получения данных от сервера.
      Делать синхронный запрос тоже неправильно, т.к. при этом у посетителя может возникнуть ощущение, что страница «зависла».

      Честно говоря, я не совсем понимаю, что вы хотите сделать (почему не подходит вариант с функцией?). Если объясните попробую помочь 😉

  • Anton

    Вячеслав, не подскажете?
    Можно ли как то получить координаты точки при помощи geocoder, что бы marker добавлять вне function?
    Типа:

    var piont = geocoder.getLatLng(address, function(response){может отсюда можно вернуть значение?})
    marker = new GMarker(point);
    map.addOverlay(marker);

    Не могу разобраться никак… =( Буду очень благодарен за помощь!

    • Проблема в том, что метод getLatLng отправляет асинхронный (ajax) запрос серверу, который может занять некоторое время.
      Т.е. строка marker = new GMarker(point) скорее всего выполнится до того как будет получен ответ.
      Именно по этому во втором параметре указывается функция, которая будет обрабатывать ответ сервера. Она гарантированно начнет выполняться после получения данных от сервера.
      Делать синхронный запрос тоже неправильно, т.к. при этом у посетителя может возникнуть ощущение, что страница «зависла».

      Честно говоря, я не совсем понимаю, что вы хотите сделать (почему не подходит вариант с функцией?). Если объясните попробую помочь 😉

  • У меня есть вопрос: а если я хочу сделать поиск по готовой карте (с отмеченными точками), как мне быть?
    Как на моем сайте

    • Я не нашел карт на вашем сайте. Поэтому спрошу, вы имеете в виду, что у вас есть отсканированная карта и вы по ней хотите искать?
      В этом случае я бы, наверное, сохранил в БД координаты точек на карте. Поиск бы делал по БД, а в зависимости от результатов показывал нужный фрагмент карты.

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

        //устанавливаем координаты и начальное приближение
        map.setCenter(new GLatLng(55.1879, 61.3757), 14);

        Мне необходимо, что бы на загрузившейся карте данная точка отображалась красным маркером.

        • Смотрите функцию addAdr (второй листинг в этой статье).
          Сам маркер добавляется так
          point = new GLatLng(…);
          marker = new GMarker(point);

  • У меня есть вопрос: а если я хочу сделать поиск по готовой карте (с отмеченными точками), как мне быть?
    Как на моем сайте

    • Я не нашел карт на вашем сайте. Поэтому спрошу, вы имеете в виду, что у вас есть отсканированная карта и вы по ней хотите искать?
      В этом случае я бы, наверное, сохранил в БД координаты точек на карте. Поиск бы делал по БД, а в зависимости от результатов показывал нужный фрагмент карты.

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

        //устанавливаем координаты и начальное приближение
        map.setCenter(new GLatLng(55.1879, 61.3757), 14);

        Мне необходимо, что бы на загрузившейся карте данная точка отображалась красным маркером.

        • Смотрите функцию addAdr (второй листинг в этой статье).
          Сам маркер добавляется так
          point = new GLatLng(…);
          marker = new GMarker(point);

  • Хорошая статья, теперь попробую по экспериментировать с картами гоогле на своем сайте.

  • Хорошая статья, теперь попробую по экспериментировать с картами гоогле на своем сайте.

  • функцию addAdr я сам нашел. понял, что в ней задан вывод маркера, я просто не пойму, как поправить код, что бы при загрузки страницы появлялся маркер, буду благодарен за конкретный кусок кода с пояснением.

    С уважением Александр

    • Примерно так
      function initialize() {
      //создаем объект для работы с картой
      map = new GMap2(document.getElementById("map_canvas"));
      if (GBrowserIsCompatible()) {
      //устанавливаем координаты и начальное приближение
      var point = new GLatLng(50.453629, 30.502838);
      map.setCenter(point , 13);
      //добавляем шкалу зума
      map.addControl(new GLargeMapControl());
      //добавляем переключатель типа карт (Карта, Спутник, Гибрид)
      map.addControl(new GMapTypeControl());
      //указываем тип карты по-умолчанию (Спутник)
      map.setMapType(G_SATELLITE_MAP);
      //создаем маркер
      marker = new GMarker(point);
      //размещаем маркер на карте
      map.addOverlay(marker);
      }
      }

      Функцию initialize я взял из примера к статье, создание маркера добавил в конец.

  • функцию addAdr я сам нашел. понял, что в ней задан вывод маркера, я просто не пойму, как поправить код, что бы при загрузки страницы появлялся маркер, буду благодарен за конкретный кусок кода с пояснением.

    С уважением Александр

    • Примерно так

      function initialize() {
      	//создаем объект для работы с картой
          map = new GMap2(document.getElementById("map_canvas"));
      	if (GBrowserIsCompatible()) {
      		//устанавливаем координаты и начальное приближение
      		var point = new GLatLng(50.453629, 30.502838);
              map.setCenter(point , 13);
      		//добавляем шкалу зума
      		map.addControl(new GLargeMapControl());
      		//добавляем переключатель типа карт (Карта, Спутник, Гибрид)
      		map.addControl(new GMapTypeControl());
      		//указываем тип карты по-умолчанию (Спутник)
      		map.setMapType(G_SATELLITE_MAP);
      		//создаем маркер
      		marker = new GMarker(point);
      		//размещаем маркер на карте
      		map.addOverlay(marker);
        	}
      }
      

      Функцию initialize я взял из примера к статье, создание маркера добавил в конец.

  • Поправил код, не помогло 🙁 маркер не появляется при загрузке страницы. Может можно сделать запрос не по координатам, а по адресу?

  • Поправил код, не помогло 🙁 маркер не появляется при загрузке страницы. Может можно сделать запрос не по координатам, а по адресу?

  • Поправлюсь, маркер не отображается при начальной загрузке только в Mozilla Firefox, в ие и опере все нормально.)

    • Странно, я тестировал код именно в FF.

      Для того, что бы поставить маркер нужны именно координаты. Но их можно получить зная адрес. Эту операцию выполняет объект GclientGeocoder (именно он используется в функции getAdress)

  • Поправлюсь, маркер не отображается при начальной загрузке только в Mozilla Firefox, в ие и опере все нормально.)

    • Странно, я тестировал код именно в FF.

      Для того, что бы поставить маркер нужны именно координаты. Но их можно получить зная адрес. Эту операцию выполняет объект GclientGeocoder (именно он используется в функции getAdress)

  • Все нормально кеш просто не сразу обновился.. хотя обновлял принудительно, в Firefox тоже показывает, спасибо за помощь.

  • Все нормально кеш просто не сразу обновился.. хотя обновлял принудительно, в Firefox тоже показывает, спасибо за помощь.

  • Jarul777

    Подскажите пожалуйста,можно ли создать переменную в неё поместить город,при загрузки, чтоб карта показывала город который в переменной?

    • Да, можно.

      Предварительно нужно узнать координаты города, либо использовать Geocoder.

      Для первого варианта код будет выглядеть примерно так.

      var kiev = new google.maps.LatLng(50.5, 30.5);

      var myOptions = {
      zoom: 4,
      center: kiev,
      mapTypeId: google.maps.MapTypeId.HYBRID
      }
      map = new google.maps.Map(document.getElementById(«map_canvas»), myOptions);

  • Огромное спасибо за статью! все так коротко и ясно описали =)

  • Pingback: jkghk « « iStore26 iStore26()

  • Dfromp

    Спасибо за информацию.
    Можете подсказать, как на карте сделать ещё 2-3 точки, если у них есть заданные адреса?

    • Просто создайте еще несколько маркеров
      var marker1 = new GMarker(point1);
      var marker2 = new GMarker(point2);
      var marker3 = new GMarker(point3);
      (их можно хранить в массиве, чтобы не создавать много переменных).
      Пример установки координат в последнем листинге в этой статье, строки 24-29.

      • Ирина

        Извиняюсь за мою глупость, но куда именно нужно вписывать координаты точек?

        • В переменную point. Код будет выглядеть примерно так:
          var point = new GLatLng(50.453629, 30.502838);
          var marker = new GMarker(point);

        • Ирина

          А тогда название этой точки куда девать, ну например я хочу назвать точку «я здесь».

        • marker.openInfoWindowHtml('Я здесь' +
          'Широта: ' + place.Point.coordinates[1] + '' +
          'Долгота: ' + place.Point.coordinates[0]);

        • Ирина

          Знаю, что надоела вам, но пожалуй спрошу. Вот то, что у меня вышло. Теперь , что бы я не вводила в окно поиска выскакивает только одна точка. Мне же нужно, чтоб когда я ввожу, например «я здесь» мне выдавало один маркер, «мама здесь» второй маркер, «брат здесь» третий и. т .д. Такое вообще реально осуществить.? Наперед огромное спасибо)

          place = response.Placemark[0];
          point = new GLatLng(51.585140, 24.740442);
          marker = new GMarker(point);

          map.addOverlay(marker);

          marker.openInfoWindowHtml('Я здесь' +
          'Широта: ' + place.Point.coordinates[1] + » +
          'Долгота: ' + place.Point.coordinates[0]);

        • Да, реально. Я сделал небольшой пример http://jsfiddle.net/vladimir_s/pahee7wz/1/, думаю, это примерно то, что вам нужно.
          Обратите внимание, в примере я использовал 3-ю версию Google Maps API, т.к. пример в статье уже устарел.

        • Ирина

          Я очень вам благодарна, но у меня есть еще последний вопрос. Можно ли это реализовать, чтоб название места вводилось именно в строке поиска.?

        • Можно. Замените список на текстовое поле ввода и кнопку «Показать» и добавьте обработчик клика по кнопке. Думаю, пример такого обработчика вы найдёте без моей помощи 🙂

        • Ирина

          Спасибо огромное)

  • Semkin

    а можно сделать так, чтобы при наборе двух точек сразу выходило расстояние между точками? 

  • Meliqsoft

    ya tak i copy paste sdelal, no vot chto browser pokazivaet—>
    Google has disabled use of the Map for this application. The provided key is not valid Google API key or it is not for Google JavaaScript API V2.    ; key=»my_key»  ya smotrel net problem, kak on sdelel generecia tan i ya paste zdelal. V chom mojet bit problema ?

    • Вы должны использовать свой собственный ключ (его можно получить на сайте google maps), а не key=»my_key». Кроме того, в третьей версии карт использовать ключ не обязательно. Советую подключать именно её.

  • Meliqsoft

    Ya rabotayu nad project CakePHP, i xochu Google map pakaxac

  • Юрий

    Здраствуйте, подскажите пожалуйста можно ли сделать вот такое. К каждой отмеченной точке прикрепить ключевые слова, чтоб когда мы вводим например «кино»,или» кинотеатр» ,или»где посмореть кино» нам выскакивали на карте метки с отмеченными кино театрами в городе.

    • Да, можно. У меня есть небольшой цикл статей, в котором показано как реализовать похожие возможности.

      • Юрий

        Спасибо большое, обизательно прочту!

  • Валентин

    Добрый день, есть возможность в этот поиск вставить скрытое значение, например аптеки… и когда вбиваешь в поиск город (допустим Москва) то выходят все аптеки г. Москва

    • Да, можно. Вопрос в каком виде хранятся данные аптек (координаты, названия и привязка к городу)? Если эти данные есть, то в функции addAdr нужно только добавить создание маркеров для аптек.

      • Валентин

        Спасибо за быстрый ответ. У меня есть данные, но как их туда втравить я не знаю, пробовал создать свою карту в гугл картах, со слоями маркеров нужных заведений… но не могу туда вставить окно поиска. и получается по всей России одни маркеры. а их более 4000. вариант второй https://developers.google.com/maps/documentation/javascript/examples/places-searchbox?hl=ru есть окно поиска и когда вбиваешь допусти Москва аптеки, поиск получается , конечно не все места аптек… но мне нужно чтобы само слово аптеки было скрыто… а вбивался только город.

        • Если есть данные аптек, то их можно добавить на страницу в виде JS массива, например:

          var pharmacies = [
          {
          'name': 'Аптека 1',
          'lat' => 40,
          'lng' => 50,
          },
          ...
          ];

          Затем этот массив можно будет использовать для создания маркеров.

        • Валентин

          спасибо

  • masha_18

    Добрый день!
    Подскажите, пожалуйста, есть ли еще варианты поиска по Google карте объектов, помимо геокодирования? (беспокоит проблема ограничения запросов в 2500 в день). Чтобы объекты были заранее отображены на карте (это также делать через массив?), и выполнялся поиск по ним

    • Для того, чтобы показать объект на карте нужны его координаты. Если у вас есть список объектов, которые нужно показывать всегда, то вы можете получить один раз их координаты, сохранить в базе данных и передавать в виде массива при загрузке страницы с картой.
      Также вы можете попробовать реализовать свой собственный сервис геокодирования. Сделать полный аналог сервиса гугла будет очень сложно, но можно попробовать сделать сервис для наиболее популярных запросов характерных именно для вашего сайта. Например, если вы знаете, что ваши пользователи часто ищут названия городов, то можно поискать готовую базу городов с координатами и использовать её в собственном сервисе для поиска.
      При этом, каждый запрос от пользователя будет отправляться сначала на ваш сервис и, если подходящий объект не найден, то на сервис геокодирования гугла.

      • masha_18

        Спасибо за ответ.
        Не совсем понятно, при запросе от пользователя, если данные с координатами объектов сохранены в базе данных и переданы в виде массива на карту Googl'а, будет ли использоваться ограничение геокодирования в 2500 запросов? (при этом пользователь в качестве запроса вводит не обязательно адрес, а, например, название, которое есть также в базе данных)
        И будет ли считаться запросом геокодирования при применении каких-либо фильтров к карте с уже нанесенными объектами?

        • Если названия и координаты объектов в вашей базе данных, то использовать геокодирование гугла не нужно. Т.е. отображение маркеров на карте запросом к службе геокодирования не является.

          Ограничение в 2500 запросов касается использования объекта

          google.maps.Geocoder
          или отправки запросов к сервису
          https://maps.googleapis.com/maps/api/geocode/

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

        • masha_18

          Спасибо. Подскажите, пожалуйста, блок с картой вставляется в какой файл, header.php?

        • Обычно нет, чаще в header.php вставляют скрипты для подключения Google Maps API.
          Блок с картой может быть в любом месте страницы, внутри тегов
          ...