Search code examples
javascriptjsongoogle-mapsgmaps.js

gmaps.js remove markers based on certain criteria


I am creating a map, using gmaps.js, that has different types of markers (parking, residence and academic). The removeMarkers() function of gmaps.js does not take any arguments, it just hides everything.

My goal is to have checkboxes for each category that show/hide the corresponding markers if the checkbox is checked or not. Similar to this JSFiddle which was linked from a previous question with a similar problem. My code is similar to the one in the mentioned question but I am getting Uncaught TypeError: Cannot read property 'length' of undefined in jquery.min.js:2in the console when I check one of the boxes. The other thing that is different is that I am getting the data from a JSON file and the storing it to an array.

Here is my code:

$.getJSON("json/map-data.json", function(data) {
    gMarkers['parking'] = [], gMarkers['academic'] = [], gMarkers['residence'] = [];
    // Loop through each feature in the JSON file
    for (var i = 0; i < data.features.length; i++) {
        features.push(data.features[i]);
        types.push(features[i].properties.type);
        descriptions.push(features[i].properties.description);
        titles.push(features[i].properties.title);
        markers.push(features[i].geometry.point);
        polygons.push(features[i].geometry.polygon);
        // store JSON data to temporary variable to later push to an array
        var markerForArray = {
            lat: markers[i][0],
            lng: markers[i][4],
            title: titles[i],
            infoWindow: {
                content: descriptions[i]
            }
        };

        // Store markerForArray sorted by "type"
        if (types[i] === 'parking')
            gMarkers['parking'].push(markerForArray);
        else if (types[i] === 'residence')
            gMarkers['residence'].push(markerForArray);
        else if (types[i] === 'academic')
            gMarkers['academic'].push(markerForArray);
    };

    /* Takes the poi type as a parameter */
    GMaps.prototype.addMarkersOfType = function (poi_type) {
        // save the relevant map
        console.log(gMarkers['parking'][0]);
        var theMap = this.map;
        // clear markers of this type
        realMarkers[poi_type]=[];
        // for each Gmaps marker
        $.each(gMarkers[poi_type],function(index, obj){
            // add the marker
            var marker = map.addMarkers(obj);
            // save it as real marker
            realMarkers[poi_type].push(marker);
       });
    }

    /* Takes the poi type as a parameter */
    GMaps.prototype.removeMarkersOfType = function (poi_type) {
        // for each real marker of this type
        $.each(realMarkers[poi_type], function(index, obj){
            // remove the marker
            obj.setMap(null);
        });
        // clear markers of this type
        realMarkers[poi_type]=[];
    }

    $('input[type="checkbox"').click(function() {
        var poi_type = $(this).attr('name');
        if ($(this).is(':checked'))
            map.addMarkersOfType(poi_type);
        else
            map.removeMarkersOfType(poi_type);
    });
});

The JSON data looks like this:

{
    "type": "Feature",
    "properties": {
        "title": "Parking Lot #1",
        "type": "parking",
        "description": ""
      },
    "geometry": {
        "point": [12.12345, -12.12345],
        "polygon":  [
            [12.12245, 12.12845],
            [12.12345,-12.12745],
            [12.12445,-12.12645],
            [12.12545,-12.12545]
        ]
    }
}

Here is my code on JSFiddle: http://jsfiddle.net/88cakes/sw9m4vyo/4/


Solution

  • I must confess I didn't try to find the issue, because your approach doesn't seem to be favorable, all these arrays where you store the different objects are unnecessary.

    Instead create for each checkbox an MVCObject , and create a property for this MVCObject whose value will be set to either the map(checked ) or null(unchecked) via a change-listener.

       mapData.features.forEach(function(item){
         //the checkbox related to the item-type
         var box= $('#'+item.properties.type);
    
         if(!box.data('mvc')){        
           //create a MVCObject and store it via checkbox-data
           box.data('mvc',new google.maps.MVCObject())
           //add a change-listener
           .change(function(){
           //set the map-property of the MVCObject to the map or null
              box.data('mvc').set('map',(box.prop('checked'))
                                          ? map.map
                                          : null)
           }).trigger('change');          
         }
    
         //create marker
         var marker=map.createMarker({
           lat:item.geometry.point[0],
           lng: item.geometry.point[1],
           map: box.data('mvc').get('map'),
           title: item.properties.title,
           infoWindow: {
              content: $('<div/>')
                        .append($('<h1/>').text(item.properties.title))
                        .append($('<p/>').text(item.properties.description))[0]
               }
         });
    
         //create polygon
         var polygon=map.drawPolygon({
           paths:item.geometry.polygon,
           map: box.data('mvc').get('map')
         });
    
         //bind the map-property of the marker & polygon
         //to the ma-property of the MVCObject
         marker.bindTo('map',box.data('mvc'),'map',true);
         polygon.bindTo('map',box.data('mvc'),'map',true);
    
       });
    

    $(window).load(function(){
       $(document).ready(function () {
           var mapData = {
               "type": "FeatureCollection",
                   "features": [{
                   "type": "Feature",
                       "properties": {
                       "title": "Parking Lot 1",
                           "type": "parking",
                           "description": ""
                   },
                       "geometry": {
                       "point": [39.298211, -70.439326],
                           "polygon": [
                           [39.298038, -70.439311],
                           [39.29804, -70.439267],
                           [39.298115, -70.439177],
                           [39.298137, -70.439177],
                           [39.298338, -70.438986],
                           [39.298472, -70.439384],
                           [39.298165, -70.439604],
                           [39.298038, -70.439311]
                       ]
                   }
               },
    
               {
                   "type": "Feature",
                       "properties": {
                       "title": "academic 1",
                           "type": "academic",
                           "description": ""
                   },
                       "geometry": {
                       "point": [39.296499, -70.435279],
                           "polygon": [
                           [39.29657, -70.434978],
                           [39.296466, -70.434965],
                           [39.296466, -70.435131],
                           [39.296412, -70.435129],
                           [39.296404, -70.435598],
                           [39.296537, -70.435606],
                           [39.296559, -70.435589],
                           [39.296563, -70.435422],
                           [39.296541, -70.435417],
                           [39.296542, -70.435378],
                           [39.296563, -70.435375]
                       ]
                   }
               },
    
               {
                   "type": "Feature",
                       "properties": {
                       "title": "residence 1",
                           "type": "residence",
                           "description": ""
                   },
                       "geometry": {
                       "point": [39.296183, -70.436438],
                           "polygon": [
                           [39.29633, -70.436782],
                           [39.296272, -70.436781],
                           [39.296257, -70.436845],
                           [39.296161, -70.436838],
                           [39.296166, -70.436602],
                           [39.296132, -70.436598],
                           [39.296118, -70.436578],
                           [39.296124, -70.436431],
                           [39.296046, -70.436417],
                           [39.296047, -70.43636],
                           [39.296001, -70.436353],
                           [39.29602, -70.436179],
                           [39.296283, -70.436197],
                           [39.296284, -70.436263],
                           [39.29627, -70.436672],
                           [39.296328, -70.4367]
                       ]
                   }
               }]
           },
    
    
           map = new GMaps({
               el: '#map',
               lat: 39.298,
               lng: -72.4375,
               zoom: 15,
               zoomControl: true
           }),
           bounds=new google.maps.LatLngBounds();
           //use checkboxes  as map-controls
           map.map.controls[google.maps.ControlPosition.RIGHT_BOTTOM].push($('.nav')[0]);
           
           mapData.features.forEach(function(item){
           
             var box= $('#'+item.properties.type);
             
             if(!box.data('mvc')){        
               //create a MVCObject and store it via checkbox-data
               box.data('mvc',new google.maps.MVCObject())
               //add a chang-listener
               .change(function(){
               //set the map-property of the MVCObject to the map or null
                  box.data('mvc').set('map',(box.prop('checked'))
                                              ? map.map
                                              : null)
               }).trigger('change');          
             }
             
             //create marker
             var marker=map.createMarker({
               lat:item.geometry.point[0],
               lng: item.geometry.point[1],
               map: box.data('mvc').get('map'),
               title: item.properties.title,
               infoWindow: {
                  content: $('<div/>')
                            .append($('<h1/>').text(item.properties.title))
                            .append($('<p/>').text(item.properties.description))[0]
                   }
             });
             
             //create polygon
             var polygon=map.drawPolygon({
               paths:item.geometry.polygon,
               map: box.data('mvc').get('map')
             });
             
             bounds.extend(marker.getPosition());
             
             //bind the map-property of the marker & polygon
             //to the ma-property of the MVCObject
             marker.bindTo('map',box.data('mvc'),'map',true);
             polygon.bindTo('map',box.data('mvc'),'map',true);
             
           });
           //bring all markers into the viewport
           map.map.fitBounds(bounds);
       });
    });
    body, html, #map {
        height: 100%;
        margin: 0;
        
    }
    .nav{
         padding:2px;
         margin:3px;
         border:1px solid #919191;
         border-radius:2px;
         background:#fff;
         text-align:right;
        }
    <script type='text/javascript' src='http://code.jquery.com/jquery-1.6.4.js'></script>
    <script type='text/javascript' src="https://maps.googleapis.com/maps/api/js"></script>
    <script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/gmaps.js/0.4.12/gmaps.min.js"></script>
    <div class="nav">
        <form>
            <label for="parking">Parking</label>
            <input type="checkbox" id="parking" value="parking" checked/>
            <br>
            <label for="academic">Academic</label>
            <input type="checkbox" id="academic" value="academic"  checked/>
            <br>
            <label for="residence">Residence</label>
            <input type="checkbox" id="residence" value="residence" />
        </form>
    </div>
    <div id="map"></div>