Пример совместного использования Google Maps API, JSON и jQuery

Автор: | 29.01.2012

В этой заметке я расскажу о том, как можно реализовать интерактивный сервис о кафе с использованием Google Maps API, jQuery и данных в формате JSON.

Пример работы можно увидеть здесь.


В начале определим контейнер для отображения карты.

<div id="map_canvas"></div>

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

<div id="map-panel" class="visible clearfix">
<div class="mp-content">
<div id="map-options" class="clearfix">
 
Map Option:
<ul>
<li>
  <a id="toggle-traffic" href="#"><em class="i-showtr"> </em><span>Show Traffic</span></a>
</li>
<li><a id="map-view" href="#">Map View</a></li>
<li><a id="sat-view" href="#">Satellite View</a></li>
</ul>
</div>
<div id="foodmap-ft-list">
<ul class="ft-list clearfix">
<li>
  <a class="ft-ftimg" href="#"><img src="img/uploads/ava_1.jpg" alt="" /></a>
  <a href="#">Warung Pecel Mbok Birah</a>
  <span class="ft-adr">Bangsri, Purwantoro</span>
  <span class="ft-status"><em class="msmall-on"> </em></span>
</li>
<li class="even">
   <a class="ft-ftimg" href="#"><img src="img/uploads/ava_2.jpg" alt="" /></a>
   <a href="#">Warung Pecel Yu Painem</a>
   <span class="ft-adr">Ndangkrang, Purwantoro</span>
   <span class="ft-status"><em class="msmall-on"> </em></span>
</li>
</ul>
</div>
</div>
 
<!--.mp-content-->
    <a class="mp-toggle" href="#"><em class="arr-close"></em></a>
  </div>

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

<div id="map-options" class="clearfix">
 
Map Option:
<ul>
<li>
  <a id="toggle-traffic" href="#"><em class="i-showtr"></em><span>Show Traffic</span></a>
</li>
<li><a id="map-view" href="#">Map View</a></li>
<li><a id="sat-view" href="#">Satellite View</a></li>
</ul>
</div>

Foodmap Список будет содержать список магазинов, которые нужно отобразить.

<div id="foodmap-ft-list">
<ul class="ft-list clearfix">
<li>
  <a class="ft-ftimg" href="#"><img src="img/uploads/ava_1.jpg" alt="" /></a>
  <a href="#">Warung Pecel Mbok Birah</a>
  <span class="ft-adr">Bangsri, Purwantoro</span>
  <span class="ft-status"><em class="msmall-on"> </em></span>
</li>
<li class="even">
  <a class="ft-ftimg" href="#"><img src="img/uploads/ava_2.jpg" alt="" /></a>
  <a href="#">Warung Pecel Yu Painem</a>
  <span class="ft-adr">Ndangkrang, Purwantoro</span>
  <span class="ft-status"><em class="msmall-on"> </em></span>
</li>
</ul>
</div>

Ссылка .mp-toggle будет использоваться как переключатель, скрыть/показать панели.

<a class="mp-toggle" href="#"><em class="arr-close"></em></a>

Нам нужно подключить еще некоторые плагины.

Такие как, скроллбар (полоса прокрутки) JscrollPane для настройки, jQuery Tweet, и самое главное, скрипт для подключения Google Maps API, и InfoWindow . Вы можете использовать плагин Marker Clusterer для управления отображением маркеров.

<script src="js/mylibs/jquery.tweet.js" type="text/javascript"><!--mce:0--></script>
<script src="js/mylibs/jScrollPane.js"></script>
<script src="js/mylibs/jquery.mousewheel.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script src="js/mylibs/infobox.js"></script>
<script src="js/mylibs/markerclusterer_packed.js"></script>

После этого мы готовим данные, которые должны отображаться на карте в формате JSON.

Пример части данных:

[{<br />
  "fId":"1",<br />
  "fName":"Warung Pecel Mbok Birah",<br />
  "latlng":"-7.850543,111.254339",<br />
  "fWeb":"http://www.example.com",<br />
  "fEmail":"pecelmbokbirah@gmail.com",<br />
  "fOpenToday":"08:00 - 15:00",<br />
  "fPhone":"0273 415 341",<br />
  "fTwitter":"google",<br />
  "fAvaPath":"ava_1.jpg",<br />
  "fImgPath":"pecel_1.jpg",<br />
  "fAdr":"Bangsri, Purwantoro"<br />
}]

Создаем необходимые функции для обратного вызова.

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

function ibCallbacks(){
  $(".tweets").each(function(){
    var username = $(this).attr("title");
    $(this).empty().tweet({username: username,count: 3,loading_text: "loading tweets...",template: "{text}  {time}"});
  })
  $(".iw-body").myTabs({hidewhat:".iw-body-main",controller:".iw-body-tabs a"});
}

Функция initisialize () используется для задания начальных параметров карты, а также стиля для отображения маркеров.

var g = google.maps;
var myLatLng = new g.LatLng(-7.850543,111.254339);
var myOptions = {
  zoom: 15,
  center: myLatLng,
  mapTypeId: g.MapTypeId.ROADMAP,
  mapTypeControl: false,
  navigationControlOptions: {
  position: g.ControlPosition.RIGHT_CENTER,
  style: google.maps.NavigationControlStyle.SMALL
  }
var map = new g.Map($("#map_canvas")[0],myOptions)
 
var image = 'img/marker.png';
var shadow = 'img/shadow.png';
var iconmark = new g.MarkerImage(image, new g.Size(32, 40));
var shadowmark = new g.MarkerImage(shadow, new g.Size(29, 25),new g.Point(0,0),new g.Point(5, 25));

Указывается центр карты:

var myLatLng = new g.LatLng(-7.850543,111.254339);

Читаем данные о кафе в формате JSON с помощью функции getJSON

$.getJSON('pecel.json', function(data){});

Затем, определяется функция обратного вызова, которая в цикле автоматически создает маркеры с существующими данными.

var newMarkers = [],marker,clatlng = [];
for (var i = 0; i < data.length; i++){
if (data[i].latlng != null){
  var strlatlng = data[i].latlng,
  fId = data[i].fId,
  fName = data[i].fName,
  fWeb = data[i].fWeb,
  fOpenStat = data[i].fOpenStat,
  fEmail = data[i].fEmail,
  fOpenToday = data[i].fOpenToday,
  fPhone = data[i].fPhone,
  fTwitter = data[i].fTwitter,
  fAdr = data[i].fAdr,
  fAvaPath = (data[i].fAvaPath=='')?'':'<img src="img/uploads/'+data[i].fAvaPath+'" />',
  fImgPath = (data[i].fImgPath=='')?'':'<img src="img/uploads/'+data[i].fImgPath+'" />';
 
  if (strlatlng.indexOf(',') > 0){
  var arrlatlng = strlatlng.split(',');
  var latlng = new g.LatLng(parseFloat(arrlatlng[0]),parseFloat(arrlatlng[1]));
  marker = new g.Marker({map: map, position: latlng,icon: iconmark,shadow: shadowmark,clickable: true});
  newMarkers.push(marker);
  clatlng.push(latlng);
 
  /** Infobox **/
var boxText = document.createElement("div");
var boxContent = '<div class="iw-wrap"> <div class="iw-content"> <div class="iw-head clearfix"> <div class="ftd-org"> <a href="#" class="ftd-ftimg">'+fAvaPath+'</a> <div class="ftd-data vcard"> <p class="org">'+fName+'</p> <p class="adr"><span class="street-address">'+fAdr+'</span></p> <div class="ftd-tools"> <ul class="clearfix"> <li><a href="'+fWeb+'"><i class="i-web"></i>Visit Website</a></li><li><a href="#" class="keep-centered" data-index="'+i+'"><i class="i-centered"></i>Keep Centered</a></li> </ul> </div> </div> </div> </div> <div class="iw-body"> <div class="iw-body-tabs"> <ul class="clearfix"> <li><a href="#ftd-info">Info Warung</a></li> <li><a href="#ftd-tweets" class="last-of-type">Tweet Terbaru</a></li> </ul> </div> <div class="iw-body-wrap"> <div class="iw-body-main" id="ftd-info"> <div class="iw-box clearfix"> <div class="iw-grid2 iw-ftimg">'+fImgPath+'</div> <div class="iw-grid1"> <p><strong>E-Mail</strong></p> <p><a href="mailto:'+fEmail+'">'+fEmail+'</a></p> <br /> <p><strong>Buka Hari Ini Jam</strong></p> <p>'+fOpenToday+'</p> <br /> <p><strong>Nomor Telepon</strong></p> <p>'+fPhone+'</p> </div> </div> </div> <div class="iw-body-main" id="ftd-tweets"> <div class="iw-box clearfix"> <div class="iw-grid3"> <div class="tweets" title="'+fTwitter+'"></div> </div> </div> </div> </div> </div> </div> </div>';
boxText.innerHTML = boxContent;
 
  var ibOptions = {
     content: boxText
    ,disableAutoPan: false
    ,maxWidth: 0
    ,pixelOffset: new g.Size(25, -90)
    ,zIndex: 99
    ,closeBoxURL: "img/close.png"
    ,infoBoxClearance: new g.Size(1, 1)
    ,isHidden: false
    ,pane: "floatPane"
    ,enableEventPropagation: false
  };
 
  newMarkers[i].infobox = new InfoBox(ibOptions);
 
  g.event.addListener(marker, 'click', (function(marker, i) {
    return function() {
    for ( h = 0; h < newMarkers.length; h++ ) {
      newMarkers[h].infobox.close();
    }
    newMarkers[i].infobox.open(map, this);
    }
  })(marker, i));
 
  g.event.addListener(newMarkers[i].infobox, 'domready', function() {
    ibCallbacks();
 
    //Keep Centered
    $(".keep-centered").click(function(e){
    e.preventDefault();
    map.setCenter(clatlng[$(this).attr("data-index")]);
    });
  });
 
  /** End Infobox **/
  }
}
}

Объявляем необходимые переменные newMarkers — массив для хранения информации для меток, переменная clatlng — значения широты и долготы для каждого маркера.

var newMarkers = [],marker,clatlng = [];

Затем, мы создаем собственную html-разметку для балуна ( InfoWindow)

var boxText = document.createElement("div");
var boxContent = '<div class="iw-wrap"> <div class="iw-content"> <div class="iw-head clearfix"> <div class="ftd-org"> <a href="#" class="ftd-ftimg">'+fAvaPath+'</a> <div class="ftd-data vcard"> <p class="org">'+fName+'</p> <p class="adr"><span class="street-address">'+fAdr+'</span></p> <div class="ftd-tools"> <ul class="clearfix"> <li><a href="'+fWeb+'"><i class="i-web"></i>Visit Website</a></li><li><a href="#" class="keep-centered" data-index="'+i+'"><i class="i-centered"></i>Keep Centered</a></li> </ul> </div> </div> </div> </div> <div class="iw-body"> <div class="iw-body-tabs"> <ul class="clearfix"> <li><a href="#ftd-info">Info Warung</a></li> <li><a href="#ftd-tweets" class="last-of-type">Tweet Terbaru</a></li> </ul> </div> <div class="iw-body-wrap"> <div class="iw-body-main" id="ftd-info"> <div class="iw-box clearfix"> <div class="iw-grid2 iw-ftimg">'+fImgPath+'</div> <div class="iw-grid1"> <p><strong>E-Mail</strong></p> <p><a href="mailto:'+fEmail+'">'+fEmail+'</a></p> <br /> <p><strong>Buka Hari Ini Jam</strong></p> <p>'+fOpenToday+'</p> <br /> <p><strong>Nomor Telepon</strong></p> <p>'+fPhone+'</p> </div> </div> </div> <div class="iw-body-main" id="ftd-tweets"> <div class="iw-box clearfix"> <div class="iw-grid3"> <div class="tweets" title="'+fTwitter+'"></div> </div> </div> </div> </div> </div> </div> </div>';
boxText.innerHTML = boxContent;
 
var ibOptions = {
   content: boxText
  ,disableAutoPan: false
  ,maxWidth: 0
  ,pixelOffset: new g.Size(25, -90)
  ,zIndex: 99
  ,closeBoxURL: "img/close.png"
  ,infoBoxClearance: new g.Size(1, 1)
  ,isHidden: false
  ,pane: "floatPane"
  ,enableEventPropagation: false
};
 
newMarkers[i].infobox = new InfoBox(ibOptions);

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

g.event.addListener(marker, 'click', (function(marker, i) {
  return function() {
    for ( h = 0; h < newMarkers.length; h++ ) {
      newMarkers[h].infobox.close();
    }
    newMarkers[i].infobox.open(map, this);
  }
})(marker, i));

Добавим обработчик для события закрытия балуна.

g.event.addListener(newMarkers[i].infobox, 'domready', function() {
  ibCallbacks()
  $(".keep-centered").click(function(e){
    e.preventDefault();
    map.setCenter(clatlng[$(this).attr("data-index")]);
  });
 });

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

var markerCluster = new MarkerClusterer(map, newMarkers);
$(".ft-name a").click(function(e){
  e.preventDefault();
  var index = $(".ft-name").index($(this).parent());
  g.event.trigger(newMarkers[index], 'click');
});

Теперь пришло время добавить несколько строк кода для настройки свойств кнопок, расположенных на панели, а именно, чтобы показать / скрыть слой карты с пробками и переключение между типами карты схема-спутник. В функцию initisialize () добавьте следующий код:

var trafficLayer = new g.TrafficLayer()
$("#map-view").click(function(){map.setMapTypeId(g.MapTypeId.ROADMAP);return false});
$("#sat-view").click(function(){map.setMapTypeId(g.MapTypeId.SATELLITE);return false});
var tog = false;
$("#toggle-traffic").click(function(){
  var icon = $("i",this),text = $("span",this);
  trafficLayer.setMap( !tog==true ? map : null );
  text.text( !tog==true ? "Hide Traffic" : "Show Traffic" );
  icon.toggleClass("i-showtr i-hidetr");
  tog = !tog;
  return false;
});

Вызов функций initisialize () и ibCallbacks()

initialize();
ibCallbacks();

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

$(".mp-toggle").click(function(e){
  e.preventDefault();
  var obj = $(this),el = $(this).parent();
  if(el.hasClass("visible")){
    el.animate({"left":"-380px"}).removeClass("visible");
    obj.find("i").toggleClass("arr-open arr-close");
  }else{
    el.animate({"left":"0"}).addClass("visible");;
    obj.find("i").toggleClass("arr-open arr-close");
  }
});
$("#foodmap-ft-list").jScrollPane();

И в самом конце, определяем необходимые CSS-стили для отображения

.map-content-wrap{
	position:relative;
	height:93%
}
 
.map-content-wrap #map_canvas{
	width:100%;
	height:100%
}
 
#map-panel{
	position:absolute;
	height:100%;
	top:0;
	left:0;
	z-index:99
}
 
#map-panel .mp-toggle{
	display:inline-block;
	background:#747047;
	padding:55px 3px;
	width:15px;
	text-align:center;
	position:absolute;
	right:-21px;
	top:21px;
	border-radius:0 5px 5px 0
}
 
#foodmap-ft-list{
	margin:10px 10px 10px 0;
	height:89%;
	overflow:auto;
	left:10px
}
 
#map-options{
	background:#f5f3e7;
	padding:5px 15px;
	margin-bottom:5px
}
 
#map-options p{
	float:left;
	margin-right:5px;
	font-size:11px;
	font-weight:bold;
	text-transform:uppercase;
	padding-top:5px
}
 
#map-options ul{
	float:left;
	display:inline-block
}
 
#map-options li{
	float:left;
	margin-left:1px;
	background:#b8b279;
	padding:1px 5px
}
 
#map-options li a,#map-options li span{
	color:#FFF;
	font-size:10px;
	text-transform:uppercase
}
 
#map-panel .mp-content, .iw-content{
	width:380px;
	z-index:99;
	height:95%;
	border-right:1px solid #747047;
	border-bottom:1px solid #747047;
	background:#FFF;
	padding:15px 0
}

Скачать архив с файлам проекта можно отсюда.

Для написания заметки использовалась статья : «Google Maps API, JSON, dan jQuery?» и код примера из нее.

Пример совместного использования Google Maps API, JSON и jQuery: 14 комментариев

  1. ILYA

    Как бы автоматизировать процесс по генерации таблицы данных JSON?

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

  2. ILYA

    Хотя это не так сложно.

    Не могу одного понять. Хочу сделать разные маркеры для разных кафе.

    там есть строчка, которая отвечает за вывод маркера
    var image = ‘img/marker.png’;

    Вместо marker.png какую то функцию надо вставить, чтобы она брала ссылки на картинки в JSONе-базе кафе и прописать ссылки на ярлыки меток в этот JSON файл для каждого кафе. А вот как это сделать и реально ли вообще?

    Подскажите пожалуйста

  3. Viacheslav

    в верху есть такие строчки

    …………..

    вот вместо …… нужно писать свой код по выводу записей

    у меня получилось примерно так

    ?php
    require(«db.php»);

    $query1= «SELECT * FROM `db_name` «;
    $result1 = mysql_query($query1);
    if(mysql_num_rows($result1)>0)
    {while ($par1 = mysql_fetch_array($result1)){

    echo ‘

    ‘.$par1[‘name’].’
    ‘.$par1[‘address’].’

    ‘;

    }

    }

    ?>

  4. smakers

    Добрый день!
    Очень хорошая статья, мне она сейчас как вода в пустыни!
    Я скачал код, добавил себе в ASP.NET проект, но при запуске страницы карта не отображается, подскажите как это можно исправить?

  5. Евгений

    Здравствуйте, как сделать этот пример для карты openstreetmap. Спасибо.

  6. Александр

    А как реализовать если есть два типа данных ресторан и магазин допустим разные шаблоны вывода информации

  7. Радомир

    Здравствуйте! у меня возникла такая проблема.Не отображаются маркеры и не работает зум на карте гугл.Что характерно не полностью загружается карта именно на главной странице http://radomirka.jino.ru ,а на странице рубрик все нормально вот пример http://radomirka.jino.ru/?place=%D0%BC%D1%83%D0%B7%D0%B5%D0%B9 Посмотрел код страниц и есть подозрения что косяк в именно в этих файлах http://radomirka.jino.ru/wp-content/themes/GeoPlaces/library/map/markerclusterer_packed.js или http://radomirka.jino.ru/wp-content/themes/GeoPlaces/library/map/markermanager.js делаю ссылками чтобы было наглядней.Не подскажете в чем проблема?Может и ошибаюсь…

    1. admin Автор записи

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

      1. Загрузите библиотеку markermanager.js просто прописав путь к ней http://google-maps-utility-library-v3.googlecode.com/svn/trunk/markermanager/src/markermanager.js

      2. Непонятная кодировка в строке var markers = {‘����������’:

      3. Ошибка в строке google.maps.event.addDomListener( document.getElementById( level ), ‘click’, function() {

      4. Непонятная кодировка в строке

      В id и name используют значения только на латинице.

  8. Радомир

    Здравствуйте!Действительно заменил markermanager.js карта действительно все заработало!!!!УРА!!!И маркеры показываются!Большое человеческое СПАСИБО!На кодировку тоже обратил внимание но вроде на сайте отображается нормально.А так я понял ее в sql таблицах менять?

  9. Никита

    Здравствуйте! Статья офигенная! Но сайт, где можно все это скачать, не работает. Добавьте пжлста архивы на ваш сайт

  10. Сергей

    Не могу к этой карте прикрепить поиск по карте!
    Пытался прикрепить к карте поиск, в итоге в форме поиска (после ввода адреса) не происходит ничего! сколько бы не жад на эНтер все бесполезно! Что здесь за ошибка какая которая мешает работать поиску!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *