Пример совместного использования 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. Сергей

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

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

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