agon024 agon024 - 1 month ago 8
Javascript Question

Google Maps - Filter results based on JavaScript object

So I have a google map that is pulling in about 185 company addresses and info from a JSON file I have got everything to work but what I want to do is filter the results when you "tick" a radio button or select an option from a select box.

Here is a working plunker - https://plnkr.co/edit/jHCuVVhGDLwgjNw4bcLr

Here is my map code:

var map;

function initialize() {
var mapOptions = {
center: new google.maps.LatLng(58, 16),
zoom: 2,
mapTypeId: google.maps.MapTypeId.TERRAIN
};
map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
}

var seg = {
1:'invesCastProd',
2:'forged',
3: 'airframe',
5: 'corp',
6: 'structurals'
}

var comp = {
1:'structurals',
2:'airfoils',
3: 'airfoils',
4: 'wyman',
5: 'energy',
6: 'strucComp',
7: 'mechHard',
8: 'engineProd',
9: 'corp',
10: 'aero',
12: 'timet',
13: 'specMetals'
}

$.getJSON("locations.json", function(json1) {
$.each(json1, function(key, data) {
var latLng = new google.maps.LatLng(data.latitude, data.longitude);
// Creating a marker and putting it on the map
var marker = new google.maps.Marker({
position: latLng
});
marker.setMap(map);

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

google.maps.event.addListener(marker, 'click', function() {

if (infoWindow) {infoWindow.close();}
infoWindow = new google.maps.InfoWindow({
content: "<h5>" + data.display_name + "</h5>" +
"<div>" + data.street+ "</div>" +
"<div>" + data.city + ", " + data.state + " &nbsp; " + data.postal_code + "</div>" +
"<div><strong>" + seg[data.segment_id] + "</strong></div>" +
"<div><strong>" + comp[data.component_id] + "</strong></div>" +
"<div class='mapPhoneNum'>" + data.telephone + "</div>" +
"<a href=" + data.web_url + ">Website</a>"
});
infoWindow.open(map, marker);
map.setZoom(15);
map.panTo(this.getPosition());

});

//############################################
// I don't know what to add here
//############################################
filterMarkers = function(){

}

});

});

// Init map
initialize();


Here is the HTML:

<div class="mapWrap">
<div id="map-canvas"></div>
<div class="investCast">
<select id="pccLoc" onchange="filterMarkers(this.value);">
<option selected="selected" disabled="disabled" value="">Please select category</option>
<option class="optGroup" value="corp">PCC Corporate</option>
<option class="optGroup" value="invesCastProd">Investment Cast Products</option>
<option class="optChild" value="structurals"> - PCC Structurals</option>
<option class="optChild" value="airfoils"> - PCC Airfoils</option>
<option class="optGroup" value="forged">Forged Products</option>
<option class="optChild" value="wyman"> - Wyman-Gordon</option>
<option class="optChild" value="energy"> - PCC Energy Group</option>
<option class="optChild" value="timet"> - Titanium Metals Corp. (TIMET)</option>
<option class="optChild" value="specMetals"> - Special Metals Corp. (SMC)</option>
<option class="optGroup" value="airProd">Airframe Products</option>
<option class="optChild" value="fasteners"> - PCC Fasteners</option>
<option class="optChild" value="aero"> - PCC Aerostructures</option>
</select>
</div>
</div>

<div class="mapSelWrap">

<div class="corpSel optGroup"><input onclick="filterMarkers(this.value);" type="radio" name="loc" value="corp" /> PCC Corporate Headquarters</div>

<div class="selInnerWrap">
<div class="selInner">
<div class="optGroup"><input onclick="filterMarkers(this.value);" type="radio" name="loc" value="invesCastProd" /> Investment Cast Products</div>
<div class="optChild"><input onclick="filterMarkers(this.value);" type="radio" name="loc" value="structurals" /> PCC Structurals</div>
<div class="optChild"><input onclick="filterMarkers(this.value);" type="radio" name="loc" value="airfoils" /> PCC Airfoils</div>
</div>
</div>

<div class="selInnerWrap">
<div class="selInner">
<div class="optGroup"><input onclick="filterMarkers(this.value);" type="radio" name="loc" value="forged" /> Forged Products</div>
<div class="optChild"><input onclick="filterMarkers(this.value);" type="radio" name="loc" value="wyman" /> Wyman-Gordon</div>
<div class="optChild"><input onclick="filterMarkers(this.value);" type="radio" name="loc" value="energy" /> PCC Energy Group</div>
<div class="optChild"><input onclick="filterMarkers(this.value);" type="radio" name="loc" value="timet" /> Titanium Metals Corp.</div>
<div class="optChild"><input onclick="filterMarkers(this.value);" type="radio" name="loc" value="specMetals" /> Special Metals Corp.</div>
</div>
</div>

<div class="selInnerWrap">
<div class="selInner">
<div class="optGroup"><input onclick="filterMarkers(this.value);" type="radio" name="loc" value="airframe" /> Airframe Products</div>
<div class="optChild"><input onclick="filterMarkers(this.value);" type="radio" name="loc" value="fasteners" /> PCC Fasteners</div>
<div class="optChild"><input onclick="filterMarkers(this.value);" type="radio" name="loc" value="aero" /> PCC Aerostructures</div>
</div>
</div>

</div>


What I am trying to do is create a "filterMarkers" function that runs when you select and option or tick a radio button that filters the pins based on segment_id and component_id (which are just numbers as you can see in the JSON file of the plunk).

And as you can also see in my plunk (https://plnkr.co/edit/jHCuVVhGDLwgjNw4bcLr) in the JavaScript file, I have created two objects ( var = seg{ }, var = comp{ } ) with my "filters" that I have matched up with the numbers in the JSON file. And it is working because when you click on a pin and the info window pops up the text in bold is the filters that are associated with the location. And I have also set the values accordingly to the filters in the HTML elements.

So how can I filter these results now based on the object variables? I am pretty far with this idea and the code I am just stuck on the filtering part.

I just don't even really know what to add into the filter function:

filterMarkers = function(){

}


Thanks for any help!

Answer

This isn't an easy one to explain...
Nice project, btw.

Here is what I changed from your Plunker, in change order:

  1. I moved the Google maps API script call from the <head> to the end of the <html>.
  2. I added async defer to it and changed the callback from initMap to initialize, which is how you named your function.
  3. I removed your initialize() call at the end of your script. It the API callback's job to trigger it.

This fixed the errors in console.
Then, I got into your question.

  1. I added some data attributes to your first radio... Since you want to filter using component_id and segment_id values from your JSON.

Here it is:

<div class="corpSel optGroup"><input onclick="filterMarkers($(this));" type="radio" name="loc" value="corp" data-segment_id="2" data-component_id="13"/> PCC Corporate Headquarters</div>

Now in your filterMarkers = function(category){, we can retreive those filtering informations.

  1. So I wrote this function:


filterMarkers = function(category){
    //console.log(category);

    console.log(category.data());
    var component = category.data("component_id");
    var segment = category.data("segment_id")

    // Clear markers
    setMapOnAll(null);
    //marker = [];
    var filteredMarkers=[];

    $.each(myJSON, function(key, data) {
        //console.log(key);

        if( (myJSON[key].component_id == component) && (myJSON[key].segment_id == segment) ){
            console.log("FOUND");

            filteredMarkers.push(key);
        }
    });

    for(i=0;i<filteredMarkers.length;i++){
        myMarkers[filteredMarkers[i]].setMap(map);
    }
}

function setMapOnAll(map) {
    for (var i = 0; i < myMarkers.length; i++) {
        myMarkers[i].setMap(map);
    }
}

NOTE: I took the setMapOnAll(map) function from the API documentation.

So the trick is to remove ALL markers from the map on each radio input click.
A "filtering" loop then checks all json objects to see if the filtering criteria match.

A temporary array (filteredMarkers) is created to hold the myMarkers array filtered keys and use it to redraw the right markers.

Updated Plunker