Search code examples
jquerygoogle-mapsgoogle-maps-api-3

Hide/Show Google Maps markers based on their category or group


I'm in the process of creating a Google Map that can show users groups of markers. Say all the restaurants or parks in an area. Currently I've been able to create a set of restaurants and a set of parks, each with their own marker color. I can even hide or show all of the markers by clicking the text under the map. But now I want to separate the markers into categories so I can hide or show them based off a checkbox. The code is below, but here are the things I'd like to do:

  1. The map should be blank with no markers by default
  2. I can separate the markers into their own categories and hide and show each category
  3. Multiple categories can be shown at a time

Here is my code

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>Google Maps Multiple Markers</title>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp"></script>
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script></script>
</head>
<body>
<div id="map" style="width: 100%; height: 650px;"></div>
<p><a onClick="clearMarkers();">Clear Markers</a></p>
<p><a onClick="showRestaurants();">Show Markers</a></p>
<script type="text/javascript">
//Restaurants Markers
var restaurants = [
    ['Melt Bar and Grill', 41.485345, -81.799047],
    ['Sloane Pub', 41.486182, -81.824178],
    ['Spitfire Salon', 41.479670, -81.768430],
    ['Mahall\'s', 41.476989, -81.781094],
    ['Szechwan Garden', 41.485615, -81.787890]
];
//Parks Markers
var parks = [
    ['Lakewood Park', 41.494457, -81.797605],
    ['Madison Park', 41.476969, -81.781929],
    ['Tuland Park', 41.464052, -81.788041]
];

var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 14,
    center: new google.maps.LatLng(41.485345, -81.799047),
    mapTypeId: google.maps.MapTypeId.ROADMAP
});

var infowindow = new google.maps.InfoWindow();

var marker, i;
var markers = new Array();

//Create and Place Restaurant Markers
for (i = 0; i < restaurants.length; i++) {  
    marker = new google.maps.Marker({
        position: new google.maps.LatLng(restaurants[i][1], restaurants[i][2]),
        map: map,
        icon: 'images/markers/red_Marker.png'
    });

    markers.push(marker);

    google.maps.event.addListener(marker, 'click', (function(marker, i) {
        return function() {
            infowindow.setContent(restaurants[i][0]);
            infowindow.open(map, marker);
        }
    })(marker, i));
}

//Create and Place Parks Markers
for (i = 0; i < parks.length; i++) {  
    marker = new google.maps.Marker({
        position: new google.maps.LatLng(parks[i][1], parks[i][2]),
        map: map,
        icon: 'images/markers/blue_Marker.png'
    });

    markers.push(marker);

    google.maps.event.addListener(marker, 'click', (function(marker, i) {
        return function() {
            infowindow.setContent(parks[i][0]);
            infowindow.open(map, marker);
        }
    })(marker, i));
}
// Sets the map on all markers in the array.
function setAllMap(map) {
  for (var i = 0; i < markers.length; i++) {
    markers[i].setMap(map);
  }
}
// Removes the markers from the map, but keeps them in the array.
function clearMarkers() {
  setAllMap(null);
}
// Shows any markers currently in the array.
function showRestaurants() {
  setAllMap(map);
}
</script>
</body>
</html>

Solution

  • A google.maps.MVCObject is a nice feature to implement this.

    Most of the google.maps-classes create MVCObjects, a Marker also is a MVCObject.

    The advantage: you may bind a property of one MVCObject to a property of another MVCObject. When the property will be changed in the source-object it will also be updated in the target-object.

    So you'll only need a MVCObject for each category. Set a property(e.g. map) of the MVCObject to either the google.maps.Map or null and bind the map-property of the markers to the map-property of the category-MVCObject, and it's done.

    To hide or show all markers set the map-property of all category-MVCObjects to the particular value(maps-instance or null).

    Sample-implementation(I've modified the structure of the categories a little bit to simplify the loops, for each category a checkbox will be created which controls the display of the related markers):

    $(window).load(function (){
    
      var places={
        restaurant:{
          label:'restaurants',
          //the category may be default-checked when you want to
          //uncomment the next line
          //checked:true,
          icon: 'http://maps.gstatic.com/mapfiles/markers2/marker.png' ,
          items: [
                  ['Melt Bar and Grill', 41.485345, -81.799047],
                  ['Sloane Pub', 41.486182, -81.824178],
                  ['Spitfire Salon', 41.479670, -81.768430],
                  ['Mahall\'s', 41.476989, -81.781094],
                  ['Szechwan Garden', 41.485615, -81.787890]
                 ]
        },
        park:{
          label:'parks',
          //the category may be default-checked when you want to
          //uncomment the next line
          //checked:true,
         icon:'http://maps.gstatic.com/mapfiles/markers2/boost-marker-mapview.png',
          items: [
                  ['Lakewood Park', 41.494457, -81.797605],
                  ['Madison Park', 41.476969, -81.781929],
                  ['Tuland Park', 41.464052, -81.788041]
                 ]
        }  
      },
      map = new google.maps.Map(
                  document.getElementById('map'), 
                  {
                    zoom: 14,
                    center: new google.maps.LatLng(41.485345, -81.799047),
                  }
                ),
      infowindow = new google.maps.InfoWindow(),
    
      // a  div where we will place the buttons
      ctrl=$('<div/>').css({background:'#fff',
                            border:'1px solid #000',
                            padding:'4px',
                            margin:'2px',
                            textAlign:'center'
                           });
      //show all-button
      ctrl.append($('<input>',{type:'button',value:'show all'})
                    .click(function(){
                      $(this).parent().find('input[type="checkbox"]')
                        .prop('checked',true).trigger('change');
                    }));
      ctrl.append($('<br/>'));
    
      //clear all-button
      ctrl.append($('<input>',{type:'button',value:'clear all'})
                    .click(function(){
                      $(this).parent().find('input[type="checkbox"]')
                        .prop('checked',false).trigger('change');
                    }));
      ctrl.append($('<hr/>'));
    
      //now loop over the categories
      $.each(places,function(c,category){
    
        //a checkbox fo the category
        var cat=$('<input>',{type:'checkbox'}).change(function(){
           $(this).data('goo').set('map',(this.checked)?map:null);
        })
          //create a data-property with a google.maps.MVCObject
          //this MVC-object will do all the show/hide for the category 
          .data('goo',new google.maps.MVCObject)
          .prop('checked',!!category.checked)
    
          //this will initialize the map-property of the MVCObject
          .trigger('change')
    
          //label for the checkbox
          .appendTo($('<div/>').css({whiteSpace:'nowrap',textAlign:'left'})
            .appendTo(ctrl))
          .after(category.label);
    
          //loop over the items(markers)
          $.each(category.items,function(m,item){
             var marker=new google.maps.Marker({
                    position:new google.maps.LatLng(item[1],item[2]),
                    title:item[0],
                    icon:category.icon
                  });
    
             //bind the map-property of the marker to the map-property
             //of the MVCObject that has been stored as checkbox-data 
             marker.bindTo('map',cat.data('goo'),'map');
             google.maps.event.addListener(marker,'click',function(){
                infowindow.setContent(item[0]);
                infowindow.open(map,this);
             });
          });
    
      });
    
     //use the buttons-div as map-control 
     map.controls[google.maps.ControlPosition.TOP_RIGHT].push(ctrl[0]);
    }
    );
    

    Demo: http://jsfiddle.net/doktormolle/brepbvww/