Организация добавления и вывода данных на карту Google Maps по категориям, используя PHP и MySQL

На страницах своего блога «Занимательная веб-картография» я уже писал, как организовать добавления данных пользователями и вывод этих данных на карту Google Maps с использованием PHP и MySQL.

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

В последующих заметках я планирую написать о том, как можно адаптировать получившийся код под 3 версию API Google Maps и как можно в месте с данными добавлять файл с изображением для балуна.

Для начала мы возьмем файлы, которые были получены в ходе работы в заметке «Google Maps – добавление меток на карту пользователями» : zapros.sql — файл с sql-кодом для создания таблицы markers; phpsqlinfo_dbinfo.php — для соединения с базой данных; phpsqlinfo_addrow.php — для записи введенных данных о метке в таблицу markers; phpsqlinfo_add.html — основной файл, который выводит карту и организует интерфейс добавления меток.

Следущие наши действия.

В базе данных MySQL мы создаем таблицу markers, используя sql-код из файла zapros.sql

Затем, нам необходимо исправить файл phpsqlinfo_dbinfo.php, изменив в нем значения параметров для соединения с базой данных на ваши: $sdb_name — имя хоста, как правило locflhost; $user_name — логин пользователя базы данных; $user_password — пароль пользователя базы данных; $db_name — название вашей базы данных.

Теперь обратившись к файлу phpsqlinfo_add.html через браузер вы должны увидеть карту Google Maps, щелкнув по карте появится маркер, по щелчку на маркере появится форма для ввода параметров метки.

Вы можете изменить значения координат начального центра карты на нужные вам в строке map.setCenter(new GLatLng(56.32811,44.0), 15); файла phpsqlinfo_add.html.

Этот же файл мы будем изменять для организации вывода меток пользователей по категориям.

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

Мы на страницу с картой добавим элементы для выбора категорий.

Для этого между строчками

 <div id="map_canvas" style="width: 800px; height: 600px"></div> и <div id="message"></div>

добавим код:

<ul id="markerTypes">
 
	<li><label for="viv_bars"><input id="viv_bars" type="checkbox" value="bar" /> Бары</label></li>
 
	<li><label for="viv_cafe"><input id="viv_cafe" type="checkbox" value="cafe" /> Кафе</label></li>
 
	<li><label for="viv_rest"><input id="viv_rest" type="checkbox" value="restaurant" /> Рестораны</label></li>			
 
</ul>

А после строки код определения стилей

 
<style type="text/css" media="screen">
 
#map_canvas { float:left; width:600px; height:400px; border:1px solid #000;}			
 
ul#markerTypes { float:left; width:500px; list-style:none; padding:0; }
 
ul#markerTypes li { padding:10px; }
 
ul#markerTypes li label{ color: #000; }
 
</style>

И отредактируем строку

<div id="map_canvas" style="width: 800px; height: 600px"></div> в вид <div id="map_canvas"></div>

Загружаем файл phpsqlinfo_add.html в браузере и наблюдаем

Теперь нам нужно организовать вывод на карту меток для выбранной категории.
Для этого нам понадобиться подключить к нашему файлу JavaScript-библиотекку jQuery, загрузить последнюю версию которой можно отсюда.

Подключаем ее добавив строку сразу после подключения API Google Maps

Две строки в начале функции инициализации карты

function initialize() {
if (GBrowserIsCompatible()) {

Заменяем на

$(document).ready(function(){

И две закрывающие скобки в конце функции }} на });

Также необходимо удалить все из тега body.

Мы сделали подготовительные операции, которые позволяют нам использовать возможности jQuery.

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

Приведу код для нашей основной функции:

 
$(document).ready(function(){
 
map = new GMap2(document.getElementById("map_canvas"));
map.setCenter(new GLatLng(56.32,44.004), 15);
 
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
 
$('#markerTypes input[type="checkbox"]').bind('click', function () {
 
var markersType = $(this).val();
 
if($(this).attr("checked")) {
 
if(!gmarkers[markersType]) {
 
gmarkers[markersType] = [];
 
$.getJSON("http://localhost/gmaps/gmaps-dob/upload.php", {markersType:markersType}, function(data){
 
setMarkers(data, markersType);				
 
});
 
}
else {
show(markersType);
}
 
}
else {
hide(markersType);
}
 
});	
 
 
 
 GEvent.addListener(map, "click", function(overlay, latlng) {
          if (latlng) {
            marker = new GMarker(latlng, {draggable:true});
            GEvent.addListener(marker, "click", function() {
              var html = "<table>" +
                         "<tr><td>Наименование:</td> <td><input type='text' id='name'/> </td> </tr>" +
                         "<tr><td>Адрес:</td> <td><input type='text' id='address'/></td> </tr>" +
                         "<tr><td>Тип:</td> <td><select id='type'>" +
                         "<option value='bar' SELECTED>Бар</option>" +
                         "<option value='restaurant'>Ресторан</option>" +
                         "<option value='cafe'>Кафе</option>" +
                         "</select> </td></tr>" +
                         "<tr><td></td><td><input type='button' value='Сохранить' onclick='saveData()'/></td></tr></form>";
 
              marker.openInfoWindow(html);
            });
            map.addOverlay(marker);
          }
        });
 
});

Обработчик события клика по карте GEvent.addListener(map, «click», function(overlay, latlng) { у нас уже был ранее.

Перед ним мы добавили обработчик события выбора соответствующей категории (checkbox), если влажок для категории установлен в асинхронном режиме с помощью функции getJSON производиться GET запрос к файлу upload.php, в котором выполняется обращение к таблице в базе данных для выбора параметров меток для данной категории.

В файле upload.php также из полученных данных формируется ответ в формате JSON, который затем передается в функцию setMarkers для обработки.

Код файла upload.php:

 
<?php
require("phpsqlinfo_dbinfo.php");
 
header('Content-Type: text/html; charset=utf-8');
 
//Не пускаем к скрипту, если это не XmlHttpRequest.
 
if( $_SERVER['HTTP_X_REQUESTED_WITH'] != 'XMLHttpRequest')
die( 'Ошибка запроса!' );
else {
 
//Проверяем на существование GET-параметр.
 
if(isset($_GET['markersType']) && !empty($_GET['markersType'])) {
 
//Доверяемся своей паранойи.
 
$markersType = mysql_real_escape_string($_GET['markersType']);
 
if($markersType == 'bar'){$markerNameType = "Бар"; $markerImg = "mm_20_red.png";}
if($markersType == 'cafe'){$markerNameType = "Кафе"; $markerImg = "mm_20_green.png";}
if($markersType == 'restaurant'){$markerNameType = "Ресторан"; $markerImg = "mm_20_blue.png";}
 
$json = '{"markers":['."n";
 
//Выполняем запрос на выборку координат маркеров соответствующего типа.
 
$query = mysql_query("SELECT  * FROM markers WHERE type = '$markersType';");
if(mysql_num_rows($query)>0)
{
while ($par = mysql_fetch_array($query)){
 
$json.= "n".'{'.'"mname": "'.$par['name'].'",';
 
$json.= '"address": "'.$par['address'].'",';
 
$json.= '"type": "'.$markerNameType.'",';
 
$json.= '"lat": "'.$par['lat'].'",';
 
$json.=  '"lon": "'.$par['lng'].'"';
 
$json.= '},';
 
}
 
$json = substr($json, 0,-1);
 
echo  $json;
 
echo '], ', "n", '"mimg": "',$markerImg.'",',"n" ,'"status": "OK"', "n", '}';
 
}
else
{
echo '{"status": "false"}';
}
 
 
//Отключаемся от БД.
 
mysql_close($link);
}
else
die('Неверны параметры запроса!');
}
?>

В функции setMarkers из полученных данных data, формируется массив меток с содержимым для балуна и добавляется на карту.

Код функции:

 
function setMarkers(data, category) {		
 
	var baseIcon = new GIcon();
	baseIcon.image = "http://webmap-blog.ru/files/gmap/gicon/" + data.mimg;
    	baseIcon.shadow = 'http://webmap-blog.ru/files/gmap/gicon/mm_20_shadow.png';
    	baseIcon.iconSize = new GSize(12, 20);
    	baseIcon.shadowSize = new GSize(22, 20);
    	baseIcon.iconAnchor = new GPoint(6, 20);
    	baseIcon.infoWindowAnchor = new GPoint(5, 1);
 
	var marker_point = new Array();
    	var html = new Array();
 
	for(var i = 0; i < data.markers.length; i++) {	
    	marker_point[i] = new GLatLng(data.markers[i].lat, data.markers[i].lon);	
	html[i] = '<strong>'+data.markers[i].mname+'</strong><br />'+data.markers[i].address;
	map.addOverlay(createMarker(marker_point[i], html[i], baseIcon, category));
	}
 
}

А функция createMarker проверяет событие клика по метке на карте из данной категории и открытия балуна с информацией.

Код функции

 
function createMarker(point, html, icon, category) {
  var marker = new GMarker(point, icon);
  marker.mycategory = category; 
  GEvent.addListener(marker, "click", function() {   
    map.openInfoWindowHtml(point, html);
  });
  gmarkers.push(marker);
  return marker;
}

И еще остались не описанными две функции show и hide — которые соответственно отображают или скрывают метки для данной категории.

Полный новый код файла phpsqlinfo_add.html:

 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html> 
  <head> 
    <title>API Google Maps добавление меток пользователями и вывод их по категориям</title> 
    <script src="http://maps.google.com/maps?file=api&amp;v=2&amp;sensor=false&amp;key=ABQIAAAAPDUET0Qt7p2VcSk6JNU1sBSM5jMcmVqUpI7aqV44cW1cEECiThQYkcZUPRJn9vy_TWxWvuLoOfSFBw" type="text/javascript"></script> 
 
<script src="jquery.min.js" type="text/javascript"></script>
 
<script type="text/javascript">
 
var map, marker, gmarkers = [];
 
$(document).ready(function(){
 
map = new GMap2(document.getElementById("map_canvas"));
map.setCenter(new GLatLng(56.32,44.004), 15);
 
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
 
$('#markerTypes input[type="checkbox"]').bind('click', function () {
 
var markersType = $(this).val();
 
if($(this).attr("checked")) {
 
if(!gmarkers[markersType]) {
 
gmarkers[markersType] = [];
 
$.getJSON("http://localhost/gmaps/gmaps-dob/upload.php", {markersType:markersType}, function(data){
 
setMarkers(data, markersType);				
 
});
 
}
else {
show(markersType);
}
 
}
else {
hide(markersType);
}
 
});	
 
 
 
 GEvent.addListener(map, "click", function(overlay, latlng) {
          if (latlng) {
            marker = new GMarker(latlng, {draggable:true});
            GEvent.addListener(marker, "click", function() {
              var html = "<table>" +
                         "<tr><td>Наименование:</td> <td><input type='text' id='name'/> </td> </tr>" +
                         "<tr><td>Адрес:</td> <td><input type='text' id='address'/></td> </tr>" +
                         "<tr><td>Тип:</td> <td><select id='type'>" +
                         "<option value='bar' SELECTED>Бар</option>" +
                         "<option value='restaurant'>Ресторан</option>" +
                         "<option value='cafe'>Кафе</option>" +
                         "</select> </td></tr>" +
                         "<tr><td></td><td><input type='button' value='Сохранить' onclick='saveData()'/></td></tr></form>";
 
              marker.openInfoWindow(html);
            });
            map.addOverlay(marker);
          }
        });
 
	        });
 
function setMarkers(data, category) {		
 
	var baseIcon = new GIcon();
	baseIcon.image = "http://webmap-blog.ru/files/gmap/gicon/" + data.mimg;
    	baseIcon.shadow = 'http://webmap-blog.ru/files/gmap/gicon/mm_20_shadow.png';
    	baseIcon.iconSize = new GSize(12, 20);
    	baseIcon.shadowSize = new GSize(22, 20);
    	baseIcon.iconAnchor = new GPoint(6, 20);
    	baseIcon.infoWindowAnchor = new GPoint(5, 1);
 
	var marker_point = new Array();
    	var html = new Array();
 
	for(var i = 0; i < data.markers.length; i++) {	
    	marker_point[i] = new GLatLng(data.markers[i].lat, data.markers[i].lon);	
	html[i] = '<strong>'+data.markers[i].mname+'</strong><br />'+data.markers[i].address;
	map.addOverlay(createMarker(marker_point[i], html[i], baseIcon, category));
	}
 
}
 
function createMarker(point, html, icon, category) {
  var marker = new GMarker(point, icon);
  marker.mycategory = category; 
  GEvent.addListener(marker, "click", function() {   
    map.openInfoWindowHtml(point, html);
  });
  gmarkers.push(marker);
  return marker;
}
 
function show(category) {
        for (var i=0; i<gmarkers.length; i++) {
          if (gmarkers[i].mycategory == category) {
            gmarkers[i].show();
          }
        }
        // == check the checkbox ==
        document.getElementById(category+"box").checked = true;
      }
 
      // == hides all markers of a particular category, and ensures the checkbox is cleared ==
      function hide(category) {
        for (var i=0; i<gmarkers.length; i++) {
          if (gmarkers[i].mycategory == category) {
            gmarkers[i].hide();
          }
        }
        // == clear the checkbox ==
        document.getElementById(category+"box").checked = false;
        // == close the info window, in case its open on a marker that we just hid
        map.closeInfoWindow();
      }
 
    function saveData() {
      var name = escape(document.getElementById("name").value);
      var address = escape(document.getElementById("address").value);
      var type = document.getElementById("type").value;
      var latlng = marker.getLatLng();
      var lat = latlng.lat();
      var lng = latlng.lng();
 
      var url = "phpsqlinfo_addrow.php?name=" + name + "&address=" + address +
                "&type=" + type + "&lat=" + lat + "&lng=" + lng;
      GDownloadUrl(url, function(data, responseCode) {
        if (responseCode == 200 && data.length <= 1) {
          marker.closeInfoWindow();
		  document.getElementById("message").innerHTML = "Данные добавлены.";
        }
      });
    }
 
</script> 
 
<style type="text/css" media="screen">
 
#map_canvas { float:left; width:600px; height:400px; border:1px solid #000;}			
 
ul#markerTypes { float:left; width:500px; list-style:none; padding:0; }
 
ul#markerTypes li { padding:10px; }
 
ul#markerTypes li label{ color: #000; }
 
</style>
 
 
  </head>
 
  <body>
    <div id="map_canvas"></div>
 
	<ul id="markerTypes">
 
			<li><label for="viv_bars"><input id="viv_bars" type="checkbox" value="bar" /> Бары</label></li>
 
			<li><label for="viv_cafe"><input id="viv_cafe" type="checkbox" value="cafe" /> Кафе</label></li>
 
			<li><label for="viv_rest"><input id="viv_rest" type="checkbox" value="restaurant" /> Рестораны</label></li>			
 
		</ul>
 
    <div id="message"></div>
 
 
 
  </body>
 
</html>

Посмотрим пример в действии.

Загружаем карту и отмечаем категорию — Бары, все метки данной категории отображаются на карте.

Щелкаем по одному из маркеров — открывается балун с информацией

Снимаем отметку с категории — маркеры удаляются с карты.

Также работает и добавление маркеров на карту.

Щелкаем по карте, а затем по появившемуся маркеру, открывается форма для ввода параметров, заполняем ее и сохраняем.

Появляется сообщение о добавлении данных.

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

После перезагрузки страницы метки отображаются уже конкретно для каждой категории.

  • Гость: ох, чувствую засяду я на месяц в изучение всех ваших примеров для своего проекта... :) очень хотелось бы, что бы Вы попробовали сделать портирование для fusion tables (использование вместо mysql)
  • Гость: да-да, всецело поддерживаю идею workdao, а именно: был бы безморно благодарен, если вы в следующих статьях опишите способ добавления пользователями данных в fusion tables
  • Гость: А можно как-то вывести названия стран по тем координатам что в Базе данных?
  • Гость: +1 за идею "описания" FT :)
  • Гость: Здравствуйте, у меня небольшой вопрос: а как сделать чтобы чекбоксы были включены по умолчанию и значки отображались.
  • Гость: А зачем? Чем больше значков одновременно отображается на карте, тем медленнее начинает браузер работать с картой. А иногда браузер может вообще зависнуть. Теперь ответ на вопрос, для включения чекбоксов изначально в параметры добавить checked="checked". И нужно организовать вывод всех значков из всех категорий при начальной инициализации карты.
  • Гость: Спасибо большое за инструкцию . Интересует вопрос как можно на основе этого сделать "кластеризацию" используя MarkerClusterer . Чтобы метки группировались если их много. А то я никак не могу разобраться. Заранее спасибо за ответ. И второй вопрос , можно ли вывести из базы данных метки на карту, если у нас нету координат, а только название городов.
  • Гость: Пробовал перевести это все в версию 3, но ничего так и не получилось. Очень хочется уже нового выпуска ;) Вроде бы и не сложно, но ничего не работает... Кстати, а как в новой версии изменился GDownloadUrl ?
  • Гость: А как сделать, чтобы карта была "резиновой" и увеличивалась уменьшалась в зависимости от разрешения экрана? Если задавать размер не в пикселях, а в процентах, то, вообще, нет карты! А при пикселях для разных разрешениях приходится каждый раз менять размеры! Может кто подскажет... Очень нужно!!!
  • Гость: Нужно добавить в стили страницы с картой html, body { margin: 0; padding: 0; }
  • Гость: На примере не отображаются маркеры.
  • Гость: Не отображались значки иконок, т.к. Google закрыл сайт http://labs.google.com откуда они брались. Я положил значки на свой блог и теперь они отображаются
  • Гость: В opere отображаются, в chrome не отображаются. Проблема браузера? Хотя на других примерах маркеры видны.
  • Гость: Приношу извенения. Теперь и в chrome работает.
  • Гость: Большое спасибо за помощь. Все работает. Я делаю сайт в joomle карту вставил в модуль html. Там есть один минус когда правишь код прямо в модуле, а потом сохраняешь,после этого карта не отображается. Но если вставить измененный код целиком все работает.
  • Гость: Сергей, вот мучаю ваш сайт уже не первый день. По этой статье несколько вопросов: 1)Ваш пример по ссылке http://webmap-blog.ru/files/gmap/phpsqlinfo_add_vcat.html у меня в chrome и Mozilla отображается в неверной кодировке, только в Opera все нормально. Красные флажки не отображаются... Баров нет в базе данных? 2)На счет изображений. Если я тестирую на localhost мне нужно менять путь к изображениям и класть их к себе? При полной копии Ваших файлов у меня на локалхосте маркеры не ставятся. Заранее благодарна за ответ
  • Гость: 1. Бары не отображались из-за пустых значений в базе данных (name, address), я их удалил и все работает. 2. Дело в том, что раньше изображения меток лежали на сайте одного из проектов Google, который был закрыт и я перенес иконки себе на блог. Поэтому на localhost при отключенном интернете они не отображаются. Надо их скопировать к себе и поправить пути в файле карты.
  • Гость: Здравствуйте на моем сайте в новых статьях перестала добавятся карта гугл , не могли бы вы за финансовае вознаграждение починить данный косяк на моем сайте?
  • Гость: Пишите адрес сайта, посмотрю в чем дело. Попробую помочь
  • Гость: Спасибо разобрался вся проблема была в плагине кеширования!
  • Гость: здравствуйте не могли бы вы скинуть исходники не получается разобраться если вас не затруднит
  • Ilnar: Не понимаю, поставил карту на сайт. http://antigai.info/forma/googlemap/phpsqlinfo_add.html метки добавляются, все нормально, но те что уже установелнны не отображаются, на карте, пробовал и бар и кафе и ресторан. Добавляю метку нажимаю сохранить, захожу в БД смотрю все нормально там она появилась, но вот на карте после перезагрузки нету? Кто нибудь знает в чем причина?
  • Keep Lane: markeri na karte zakidivaet v bazu, no na karte nechego ne pokazivaet