Home > Enterprise >  Google Maps Filter Javascript
Google Maps Filter Javascript

Time:07-13

Looking for a way to filter the map markers using pure javascript based upon multiple conditions if they exist. This is based upon having potentially 4 potential filters possible.

So imagine I have two or more field sets

  • Project Type (this will be an array of project types ['engineering','construction'])
  • Region (this will be an array of regions ['France','Italy'])
  • Name (this will be string input 'google')
  • Value (integer input '1000000')

I want to filter through the markers and then include those with matching criteria. And exclude the matching criteria if it doesn't exist or have a value set.

Example1: engineering, france, google, 1000000 Example2: construction, italy Example3: engineering, france, 1000000

Trying to achieve this in an elegant manner and not get into a nested if statement pit of hell.

Here is a working example I have setup, which accounts for two filters but isn't as clean as I would like and allow for the inclusion of extra filters easily.

Looking to have it accurately show the information based upon the users selections. So if they choose multiple projects then show them but if they are include a region and a value show where the project type, location and other match.

function initMap() {
  map = new google.maps.Map(document.getElementById("map"), {
    zoom: 5,
    center: { lat: -25.77649954803059, lng: 122.03240276153382 },
    styles: darkMapStyle,
  });

  // Define Filter Arrays
  let project_typeFilters = [];
  let regionFilters = [];

  // Reset filter on reload
  resetFitlers();

  const infoWindow = new google.maps.InfoWindow({
    content: "",
    disableAutoPan: true,
  });

  // Add some markers to the map.
  for (let i = 0; i < projectData.length; i  ) {
    let new_marker = new google.maps.Marker({
      position: { lat: projectData[i].lat, lng: projectData[i].lng },
      title: projectData[i].project_title,
    });

    // Add marker to map
    new_marker.setMap(map);

    new_marker.region = projectData[i].region.toLocaleLowerCase();
    new_marker.project_type = projectData[i].project_type.toLowerCase();

    markers.push(new_marker);
  }

  console.log(markers);

  // Filter Specific
  function filterMining() {
    for (let i = 0; i < markers.length; i  ) {
      if (markers[i].project_type == "Mining") {
        markers[i].setMap(map);
      } else {
        markers[i].setMap(null);
      }
    }
  }

  // Filter Specific
  function filterData() {
    //
    for (let i = 0; i < markers.length; i  ) {
      if (project_typeFilters.length > 0 && regionFilters.length > 0) {
        // Filter/Show if both are true
        if (
          project_typeFilters.includes(markers[i].project_type) &&
          regionFilters.includes(markers[i].region)
        ) {
          markers[i].setMap(map);
          continue;
        }
      } else if (project_typeFilters.length > 0 || regionFilters.length > 0) {
        // Filter/Show for either
        if (
          project_typeFilters.includes(markers[i].project_type) ||
          regionFilters.includes(markers[i].region)
        ) {
          markers[i].setMap(map);
          continue;
        }
      }
      if (project_typeFilters.length == 0 && regionFilters.length == 0) {
        markers[i].setMap(map);
        continue;
      }
      markers[i].setMap(null);
    }
  }

  // Reset and show all
  function showAll() {
    resetFitlers();
    for (let i = 0; i < markers.length; i  ) markers[i].setMap(map);
  }

  // Reset input and clear filter arrays
  function resetFitlers() {
    document.querySelectorAll(".filter").forEach((item) => {
      item.checked = false;
    });
    project_typeFilters = [];
    regionFilters = [];
  }

  document.getElementById("reset").onclick = showAll;

  document.querySelectorAll(".filter").forEach((item) => {
    item.addEventListener("click", () => {
      let type = item.getAttribute("data-type");
      let value = item.getAttribute("id");
      if (
        item["checked"] &&
        project_typeFilters.includes(value) === false &&
        type === "project_type"
      ) {
        project_typeFilters.push(value);
      }
      if (
        item["checked"] &&
        regionFilters.includes(value) === false &&
        type === "region"
      ) {
        regionFilters.push(value);
      }
      if (item["checked"] === false && type === "project_type") {
        const index = project_typeFilters.findIndex(
          (string) => string === value
        );
        project_typeFilters.splice(index, 1);
      }
      if (item["checked"] === false && type === "region") {
        const index = regionFilters.findIndex((string) => string === value);
        regionFilters.splice(index, 1);
      }
      filterData();
    });
  });
}

window.initMap = initMap;

Example of projectData JSON

let projectData = [
  {
    id: 1,
    lat: -24.957874041168797,
    lng: 118.5013331401608,
    label: "Project Name #1",
    project_title: "Project #1 Title",
    project_url: "https://youtube.com.au",
    project_type: "Engineering",
    region: "France",
    value: "1000000",
    company: "Company Name",
    company_url: "https://www.google.com.au",
    company_email: "[email protected]",
    project_description:
      "Bacon ipsum dolor amet kielbasa pastrami beef ribs pig cow. Chicken kielbasa boudin, spare ribs doner sausage short loin beef meatloaf tenderloin chislic sirloin ground round pastrami bacon. Meatball meatloaf sausage spare ribs hamburger, kielbasa strip steak ball tip pork belly flank venison. Tongue meatloaf drumstick, sausage alcatra hamburger shankle.",
  },
{
    id: 2,
    lat: -32.83626802206395,
    lng: 116.47405764163521,
    label: "Project Name #2",
    project_title: "Project #2 Title",
    project_url: "https://youtube.com.au",
    project_type: "Construction",
    region: "Italy",
    value: "1000000",
    company: "Company Name",
    company_url: "https://www.google.com.au",
    company_email: "[email protected]",
    project_description:
      "Bacon ipsum dolor amet kielbasa pastrami beef ribs pig cow. Chicken kielbasa boudin, spare ribs doner sausage short loin beef meatloaf tenderloin chislic sirloin ground round pastrami bacon. Meatball meatloaf sausage spare ribs hamburger, kielbasa strip steak ball tip pork belly flank venison. Tongue meatloaf drumstick, sausage alcatra hamburger shankle.",
  },
  {
    id: 3,
    lat: -24.957874041168797,
    lng: 118.8013331401608,
    label: "Project Name #3",
    project_title: "Project #3 Title",
    project_url: "https://youtube.com.au",
    project_type: "Construction",
    region: "France",
    value: "1000000",
    company: "Company Name",
    company_url: "https://www.google.com.au",
    company_email: "[email protected]",
    project_description:
      "Bacon ipsum dolor amet kielbasa pastrami beef ribs pig cow. Chicken kielbasa boudin, spare ribs doner sausage short loin beef meatloaf tenderloin chislic sirloin ground round pastrami bacon. Meatball meatloaf sausage spare ribs hamburger, kielbasa strip steak ball tip pork belly flank venison. Tongue meatloaf drumstick, sausage alcatra hamburger shankle.",
  },
  {
    id: 4,
    lat: -21.218106010814925,
    lng: 119.86911455192619,
    label: "Project Name #4",
    project_title: "Project #4 Title",
    project_url: "https://youtube.com.au",
    project_type: "Engineering",
    region: "Italy",
    value: "1000000",
    company: "Company Name",
    company_url: "https://www.google.com.au",
    company_email: "[email protected]",
    project_description:
      "Bacon ipsum dolor amet kielbasa pastrami beef ribs pig cow. Chicken kielbasa boudin, spare ribs doner sausage short loin beef meatloaf tenderloin chislic sirloin ground round pastrami bacon. Meatball meatloaf sausage spare ribs hamburger, kielbasa strip steak ball tip pork belly flank venison. Tongue meatloaf drumstick, sausage alcatra hamburger shankle.",
  },
  {
    id: 5,
    lat: -21.318106010814925,
    lng: 119.86911455192619,
    label: "Project Name #5",
    project_title: "Project #5 Title",
    project_url: "https://youtube.com.au",
    project_type: "Engineering",
    region: "France",
    value: "1000000",
    company: "Company Name",
    company_url: "https://www.google.com.au",
    company_email: "[email protected]",
    project_description:
      "Bacon ipsum dolor amet kielbasa pastrami beef ribs pig cow. Chicken kielbasa boudin, spare ribs doner sausage short loin beef meatloaf tenderloin chislic sirloin ground round pastrami bacon. Meatball meatloaf sausage spare ribs hamburger, kielbasa strip steak ball tip pork belly flank venison. Tongue meatloaf drumstick, sausage alcatra hamburger shankle.",
  },

CodePudding user response:

Given the lack of HTML, the minimal dataset and slightly fuzzy requirements the following might ( or might not ) be the sort of thing you are looking for. I have used this approach before to filter markers on a map where the dataset was much, much larger and the number of criteria was also much larger.

The filtering of markers is handled within the changehandler function - the comments in the code will help it make sense. You should be able to adapt the logic to checkboxes

<!DOCTYPE html>
<html lang='en'>
    <head>
        <meta charset='utf-8' />
        <title>Google Maps: Filter markers based upon user selected options</title>
        <style>
            body{
                width:100%;height:100vh;margin:0;padding:0;box-sizing:border-box;
            }
            #map{
                width:900px;
                height:600px;
                float:none;
                margin:5rem auto 0;
            }
            form{
                display:flex;
                width:100%;
                flex-direction:row;
                justify-content:center;
                margin:1rem auto;
            }
            select.filter{
                padding:0.75rem;
                margin:0.25rem;
                flex:1
            }
            p{
                width:900px;
                margin:auto;
                float:none;
            }
            form *,p{
                font-family:monospace
            }
        </style>
        <script>
            // utility shortcuts
            const q=(e,n=document)=>n.querySelector(e);
            const qa=(e,n=document)=>n.querySelectorAll(e);
            
            let projectData = [
              {
                id: 1,
                lat: -24.957874041168797,
                lng: 118.5013331401608,
                label: "Project Name #1",
                project_title: "Project #1 Title",
                project_url: "https://youtube.com.au",
                project_type: "Engineering",
                region: "France",
                value: "1000000",
                company: "Company Name",
                company_url: "https://www.google.com.au",
                company_email: "[email protected]",
                project_description:
                  "Bacon ipsum dolor amet kielbasa pastrami beef ribs pig cow",
              },
            {
                id: 2,
                lat: -32.83626802206395,
                lng: 116.47405764163521,
                label: "Project Name #2",
                project_title: "Project #2 Title",
                project_url: "https://youtube.com.au",
                project_type: "Construction",
                region: "Italy",
                value: "1000000",
                company: "Company Name",
                company_url: "https://www.google.com.au",
                company_email: "[email protected]",
                project_description:
                  "Bacon ipsum dolor amet kielbasa pastrami beef ribs pig cow",
              },
              {
                id: 3,
                lat: -24.957874041168797,
                lng: 118.8013331401608,
                label: "Project Name #3",
                project_title: "Project #3 Title",
                project_url: "https://youtube.com.au",
                project_type: "Construction",
                region: "France",
                value: "1000000",
                company: "Company Name",
                company_url: "https://www.google.com.au",
                company_email: "[email protected]",
                project_description:
                  "Bacon ipsum dolor amet kielbasa pastrami beef ribs pig cow",
              },
              {
                id: 4,
                lat: -21.218106010814925,
                lng: 119.86911455192619,
                label: "Project Name #4",
                project_title: "Project #4 Title",
                project_url: "https://youtube.com.au",
                project_type: "Engineering",
                region: "Italy",
                value: "1000000",
                company: "Company Name",
                company_url: "https://www.google.com.au",
                company_email: "[email protected]",
                project_description:
                  "Bacon ipsum dolor amet kielbasa pastrami beef ribs pig cow",
              },
              {
                id: 5,
                lat: -21.318106010814925,
                lng: 119.86911455192619,
                label: "Project Name #5",
                project_title: "Project #5 Title",
                project_url: "https://youtube.com.au",
                project_type: "Engineering",
                region: "France",
                value: "1000000",
                company: "Company Name",
                company_url: "https://www.google.com.au",
                company_email: "[email protected]",
                project_description:
                  "Bacon ipsum dolor amet kielbasa pastrami beef ribs pig cow",
              }
            ];
            
            
            function initMap() {
                let markers=[];
                let Filters={};
                
                const map = new google.maps.Map( q('#map'), {
                    zoom: 5,
                    center: { lat: -25.77649954803059, lng: 122.03240276153382 }
                });
                
                const infoWindow = new google.maps.InfoWindow({
                    disableAutoPan: false,
                });
                
                const clickhandler=function(e){
                    /* 
                        open the infowindow and display the properties 
                        from the JSON data for this marker in a very 
                        basic format... 
                    */
                    infoWindow.open( map, this );
                    infoWindow.setPosition( this.position );
                    infoWindow.setContent( Object.keys( this.data ).map( k=>[ k, this.data[ k ] ].join(': ') ).join('<br />') );
                };
                
                // the filter function
                const changehandler=(e)=>{
                    let bounds=new google.maps.LatLngBounds();
                    /* 
                        If the "select" menu has an option, other than the 1st, 
                        selected we add it to our list of Filters.
                    */
                    if( e.target.selectedIndex==0 && Filters.hasOwnProperty( e.target.name ) ){
                        delete Filters[ e.target.name ];
                    }else{
                        Filters[ e.target.name ]=e.target.value;
                    }
                    
                    // hide any open infowindow
                    infoWindow.close();
                    
                    // hide ( not remove ) all markers
                    markers.forEach( mkr=>mkr.setVisible( false ) );
                    
                    
                    /*
                        Iterate through all markers and continually
                        set the boolean value res by validating that the
                        current Select value matches the appropriate value
                        from the source data.
                    */
                    let filtered=markers.filter( function( mkr ){
                        let res=true;
                        Object.keys( Filters ).forEach( name => {
                            /* this is the important bit ! */
                            res = res && Filters[ name ]===mkr.data[ name ];
                        });
                        return res;
                    });
                    
                    /*
                        with the returned array of matched markers we
                        now set their visibility so that they are visible.
                    */
                    filtered.forEach( mkr=>{
                        mkr.setVisible( true );
                        bounds.extend( mkr.position );
                    });
                    
                    if( !bounds.isEmpty() ) map.fitBounds( bounds );
                };
                
                // add the markers...
                projectData.forEach(json=>{
                    let args={
                        position: { lat:Number( json.lat ), lng:Number( json.lng ) },
                        title:json.project_title,
                        data:json,/* This is ALL the json data for this marker - this is used in the filter!! */
                        map:map
                    };
                    let marker=new google.maps.Marker( args );
                    google.maps.event.addListener( marker, 'click', clickhandler );
                    
                    markers.push( marker );
                });
                
              
                //assign change event handlers to select menus
                qa('.filter').forEach(n=>{
                    n.addEventListener( 'change', changehandler );
                });
            }
        </script>
    </head>
    <body>
        <div id='map'></div>
        <form>
            <!--
                Note that the names of these "SELECT" menus match the keys
                within the JSON source data. This is important with the above
                code as the name is used to filter the data.
                
                If the elements cannot be so named then a lookup matrix
                would be required which just adds another layer of complexity.
            -->
            <select name='project_type' class='filter'>
                <option selected>Please select "Project Type"
                <option>Engineering
                <option>Construction
            </select>
            
            
            <select name='project_title' class='filter'>
                <option selected>Please select "Project Title"
                <option>Project #1 Title
                <option>Project #2 Title
                <option>Project #3 Title
                <option>Project #4 Title
                <option>Project #5 Title
            </select>
        

            <select name='region' class='filter'>
                <option selected>Please select "Region"
                <option>France
                <option>Italy
            </select>

        

            <select name='company_name' class='filter'>
                <option selected>Please select "Company Name"
                <option>Google
                <option>Yahoo
            </select>
            

            <select name='value' class='filter'>
                <option selected>Please select "Value"
                <option>1000000
                <option>2000000
            </select>
        </form>
        <script async defer src='//maps.googleapis.com/maps/api/js?key=<APIKEY>&callback=initMap'></script>
    </body>
</html>

Proof of concept

  • Related