При создании справочных ресурсов с использованием карт часто возникает проблема, как показать ближайшие объекты для того или иного пользователя.
В этой заметке я расскажу как это сделать, с использованием API Google Maps v3.
Для примера мы будем искать ближайшие кафе в Нижнем Новгорде.
Пользователь вводит свой адрес в форму над картой и радиус поиска в километрах, ему выдается найденный результат на карте, а слева от карты список кафе отсортированный по растоянию.
В начале необходимо подготовить исходные данные о кафе.
Они взяты из открытых источников в интернете.
Затем, с помощью скрипта из заметки «Используем HTML-геокодер для Google Maps JavaScript API v3», были получены значения координат для собранных адресов и записаны в базу данных.
Как работает данный пример.
Введенное пользователем значение адреса, мы используя геокодер API Google Maps v3 преобразуем в пару координат — значения широрты и долготы, которые затем в месте с радиусом передаем скрипту phpsqlsearch_genjson.php.
В данном скрипте производится специальный запрос к таблице в базе данных, в результате мы получаем сведения об организациях попадающих в окружность заданного радиуса и с определенным центром.
Данные сортируются по расстоянию от центра окружности.
Вот код запроса:
$query = sprintf("SELECT address, name, rayon, lat, lng, ( 6371 * acos( cos( radians('%s') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( lat ) ) ) ) AS distance FROM markers_ussearch HAVING distance < '%s' ORDER BY distance LIMIT 0 , 50", mysql_real_escape_string($lat), mysql_real_escape_string($lng), mysql_real_escape_string($lat), mysql_real_escape_string($radius)); |
Из массива полученных данных формируется ответ в формате JSON, который отправляется на страницу с картой.
Полный код файла phpsqlsearch_genjson.php:
<?php header("Content-type: text/html;charset=UTF-8"); require("config.php"); $lat = $_GET["lat"]; $lng = $_GET["lng"]; $radius = $_GET["radius"]; $query = sprintf("SELECT address, name, rayon, lat, lng, ( 6371 * acos( cos( radians('%s') ) * cos( radians( lat ) ) * cos( radians( lng ) - radians('%s') ) + sin( radians('%s') ) * sin( radians( lat ) ) ) ) AS distance FROM markers_ussearch HAVING distance < '%s' ORDER BY distance LIMIT 0 , 50", mysql_real_escape_string($lat), mysql_real_escape_string($lng), mysql_real_escape_string($lat), mysql_real_escape_string($radius)); $result = mysql_query($query); if (!$result) { die("Invalid query: " . mysql_error()); } while ($par1 = mysql_fetch_array($result)){ $places[] = array("name"=>$par1['name'], "address" => $par1['address'], "rayon" => $par1['rayon'], "lat" => $par1['lat'], "lng" => $par1['lng']); } $json = json_encode($places); echo $json; ?> |
Файл config.php служит для соединения с базой данных и имеет следующий код:
<?php $sdb_name = "localhost"; $user_name = "root"; $user_password = ""; $db_name = "gmap_bd"; // соединение с сервером базы данных if(!$link = mysql_connect($sdb_name, $user_name, $user_password)) { echo "<br>Не могу соединиться с сервером базы данных<br>"; exit(); } // выбираем базу данных if(!mysql_select_db($db_name, $link)) { echo "<br>Не могу выбрать базу данных<br>"; exit(); } mysql_query('SET NAMES utf8'); ?> |
Давайте теперь рассмотрим код основного файла usersearch_gmapv3_radius.html
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Поиск по своим данным от произвольной точки в пределах окружности заданного радиуса, с выводом на Google Maps</title> <script src="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <script type="text/javascript"> var map, infoWindow, userMarker = [], side_bar_html = ""; var gmarkers = new Array(); var infowindow = new google.maps.InfoWindow( { size: new google.maps.Size(150,50) }); function createMarker(latlng, name, html) { var contentString = html; var marker = new google.maps.Marker({ position: latlng, map: map }); google.maps.event.addListener(marker, 'click', function() { infowindow.setContent(contentString); infowindow.open(map,marker); }); gmarkers.push(marker); side_bar_html += '<a href="javascript:myclick(' + (gmarkers.length-1) + ')">' + name + '</a><br>'; } function initialize() { map = new google.maps.Map(document.getElementById("map"), { center: new google.maps.LatLng(56.317213,43.993976), zoom: 12, mapTypeId: 'roadmap', mapTypeControlOptions: {style: google.maps.MapTypeControlStyle.DROPDOWN_MENU} }); infoWindow = new google.maps.InfoWindow(); } function searchLocations() { var address = $('#addressLoc').val(); var radius = $('#radiusSelect').val(); var geocoder = new google.maps.Geocoder(); geocoder.geocode({address: address}, function(results, status) { if (status == google.maps.GeocoderStatus.OK) { var locations_lat = results[0].geometry.location.lat(); var locations_lng = results[0].geometry.location.lng(); while(userMarker[0]){ userMarker.pop().setMap(null); } var myLatLng = new google.maps.LatLng(locations_lat, locations_lng); userMarker[0] = new google.maps.Marker({ position: myLatLng, map: map, icon: 'home-1.png' }); var bounds = new google.maps.LatLngBounds(); clearOverlay(); var sidebar = $("#sidebar").html(); $("#sidebar").html(sidebar); //Загружаем данные в формате JSON из файла phpsqlsearch_genjson.php $.getJSON("phpsqlsearch_genjson.php", {lat : locations_lat, lng : locations_lng, radius:radius }, function(json){ var marker; if (json.length == null) { $("#sidebar").html('Ничего не найдено.'); return; } for (i = 0; i < json.length; i++) { var name = json[i].name; var address = '<strong>'+name+'</strong><br>'+json[i].address+'<br >Район: '+json[i].rayon; var point = new google.maps.LatLng(json[i].lat, json[i].lng); marker = createMarker(point, name, address); bounds.extend(point); } map.fitBounds(bounds); $("#sidebar").append(side_bar_html); }); } else { alert(address + ' not found'); } }); } function myclick(i) { var latLng = gmarkers[i].getPosition(); map.setCenter(latLng); map.setZoom(17); google.maps.event.trigger(gmarkers[i], "click"); } function clearOverlay() { infoWindow.close(); for (var i = 0; i < gmarkers.length; i++) { gmarkers[i].setMap(null); } gmarkers.length = 0; side_bar_html = ""; $("#sidebar").html(""); } </script> <style type="text/css"> html, body { height: 100%; } font-family: Arial, Helvetica, sans-serif; font-size: 10px; </style> </head> <body onload="initialize()"> <p>Ваш адрес: <input type="text" id="addressLoc" size="40" value="Нижний Новгород, "/> Радиус поиска в км: <input type="text" id="radiusSelect" size="5"/> <input type="button" onclick="searchLocations()" value="Найти"/> </p> <div id="mymap_div" style="width:1050px;"> <div id="sidebar" style="float:left; width: 250px; height: 600px; overflow: auto;"></div> <div id="map" style="margin-left: 250px; width: 800px; height:600px;"></div> </div> </body> </html> |
В начале мы после подключения API Google Maps, добавляем к нашему html-файлу javascript-библиотеку Jquery, для выполнения асинхронных запросов.
По клику на кнопке «Найти», вызывается функция searchLocations, в которой мы получаем введенные данные из формы, производим геокодирование адреса и отправляем запрос скрипту phpsqlsearch_genjson.php, а затем принимаем полученный ответ в формате JSON.
Функция createMarker — добавляет метку на карту и ссылку в слайдбар.
Функция myclick обрабатывает клик по ссылке в слайдбаре, происходит центрирование и масштабирование карты на нужной метке.
Функция clearOverlay — служит для удаления предыдущего результата поиска.
Скачать архив с файлами примера
Для написания заметки использовались примеры из следующих статей «Реализация поиска по данным пользователя с использованием API Google Maps v3» на моем блоге и «Creating a Store Locator with PHP, MySQL & Google Maps».
Отличная вещь, спасибо огромное, но есть вопрос…
Как я понял, скрипт ищет не кафе, а данные из БД по координатам — то, что есть близко к объекту. Вопрос — необходимо самому создавать эту БД со всеми кафе или прочими центрами услуг? Или как-то интегрируются данные из данных Гугла? Например, я бы хотел, чтобы пользователь находил супермаркеты. В идеале, конечно, чтобы был выпадающий список (кафе, супермаркет, техобслуживание и т.д.), но думаю, что это тема отдельного урока.
То есть суть вопроса — как и где находить необходимые объекты для БД? Спасибо!
Нужно создавать базу данных самому. Можно еще использовать сервис Google Places API, но есть проблема с содержанием базы по городам России, если по Москве и Санкт-Петербургу много данных, то по другим городам они могут быть минимальными или вообще отсутствовать.
Можно еще использовать API 2GIS
Спасибо, будем пробовать!
Наткнулся на урок по этому вопросу http://www.script-tutorials.com/google-places-api-practice/comment-page-1/ но почему-то не смог приспособить к своей местности — упрямо показывает только узкий спектр и только в том месте, про который пример (Нью-Йорк). Подозреваю, что где-то идет запрос в БД, но нигде в коде не смог обнаружить этого запроса. Если Вам будет интересно, то было бы прекрасно, если выложите здесь этот урок, думаю всем будет полезно. Спасибо за уроки!
Как переделать запрос чтобы выводились обекты которые лежат между двумя точками, учитывать например только долготу
В файле «phpsqlsearch_genjson.php» echo $json выводит null
Может я что-то не так пишу в запросе?
Не могли бы Вы расписать сам запрос более подробно? Что значит цифра 6371? И вообще вся эта длинная конструкция которая потом объявляется как distance — для чего это все? )
Спасибо.
И еще сразу вопрос: зачем нужны эти записи:
$lat = $_GET[«lat»];
$lng = $_GET[«lng»];
$radius = $_GET[«radius»];
Каким образом например все эти переменные окажутся в $_GET если мы туда ничего не передаем вроде…