Wern Ancheta

Adventures in Web Development.

Building a Nearby Places Search App With Google Places API

| Comments

In this tutorial were going to build an app that would allow users to search for a specific place and then find nearby places based on a specific category. Such as restaurants, churches, and schools. We will implement the app with Google Maps, Google Places and PHP.

Getting API Credentials

First you need to get API Credentials from your Google Console and then enable the Google Maps and Google Places API. If you don’t know how to do that, feel free to ask Google. I believe this topic has already been written before. Here are the APIs that you need to enable:

  • Google Maps JavaScript API
  • Google Places API Web Service

Building the App

Now were ready to build the app. First lets work on the back-end side of things.

Getting Results from the Places API

To make our life easier, were going to use a library for making the request to the Google Places API. Add the following in your composer.json file:

1
2
3
4
5
{
    "require": {
        "joshtronic/php-googleplaces": "dev-master"
    }
}

Once you’re done, execute composer install on your terminal to install the library. Now we can use the library like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

require 'vendor/autoload.php';

$google_places = new joshtronic\GooglePlaces('YOUR_GOOGLE_API_KEY');

$lat = $_POST['lat']
$lng = $_POST['lng'];
$place_types = $_POST['place_types'];

$google_places->location = array($lat, $lng);
$google_places->radius = 8046; //hard-coded radius
$google_places->types = $place_types;
$nearby_places = $google_places->nearbySearch();

?>

Breaking it down. First we include the autoload file so we can access the library from our file:

1
2
3
<?php
require 'vendor/autoload.php';
?>

Next, we created a new instance of the GooglePlaces class. You need supply the API Key that you got earlier from your Google Console:

1
2
3
<?php
$google_places = new joshtronic\GooglePlaces('YOUR_GOOGLE_API_KEY');
?>

Next, we get the data that we will be supplying later on in the client-side and assign them to their own variables:

1
2
3
4
5
<?php
$lat = $_POST['lat']
$lng = $_POST['lng'];
$place_types = $_POST['place_types'];
?>

Lastly, we make the actual request to the Google Places API. This library works a little bit different from your usual one. In the sense that we pass in the parameters needed by the actual search method using the object that we got from declaring a new instance of the GooglePlaces class. The first thing that we need to pass is the location, this takes up an array containing the coordinates (latitude and longitude) of the place that we are using as a reference point. This is basically the place where we are at, the place where we want to find nearby places on. Next you need to supply the radius. This is how many meters from your reference point you want your search to be limited. In this case we supplied a hard-coded value of 8046 meters, which is about 8 kilometers. If you want the user to have more control over this value, you can try adding a slider that the user can use to change the radius. And the last one is the types, this is an array of the types of places you want to see in the results. An example of this is restaurants (yeah I’m hungry so I mentioned this twice now), parks, shopping center, etc. Once you’ve supplied those, you can now call the nearbySearch method. This will make the request to the API and return the data that we need. We just have to turn it into a JSON string so it can be parsed and read later on from the client-side.

1
2
3
4
5
6
7
8
<?php
$google_places->location = array($lat, $lng);
$google_places->radius = 8046; //hard-coded radius
$google_places->types = $place_types;
$nearby_places = $google_places->nearbySearch();

echo json_encode($nearby_places);
?>

Creating the Map

Next we move on to the client-side. Create a new index.html file and put the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>gmap</title>
  <link rel="stylesheet" href="style.css">
  <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
  <script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=YOUR_GOOGLE_API_KEY&sensor=false&libraries=places"></script>
</head>
<body>
  <div id="map-container">
    <input type="text" id="search">
    <div id="map-canvas"></div>
  </div>

  <div id="place-types">
    <ul>
      <li>
        <input type="checkbox" data-type="bar"> bar
      </li>
      <li>
        <input type="checkbox" data-type="bus_station"> bus station
      </li>
      <li>
        <input type="checkbox" data-type="hospital"> hospital
      </li>
      <li>
        <input type="checkbox" data-type="health"> health
      </li>
      <li>
        <input type="checkbox" data-type="police"> police
      </li>
      <li>
        <input type="checkbox" data-type="post_office"> post office
      </li>
      <li>
        <input type="checkbox" data-type="store"> store
      </li>
      <li>
        <input type="checkbox" data-type="library"> library
      </li>
      <li>
        <input type="checkbox" data-type="fire_station"> fire station
      </li>
      <li>
        <input type="checkbox" data-type="gas_station"> gas station
      </li>
      <li>
        <input type="checkbox" data-type="convenience_store"> convenience store
      </li>
      <li>
        <input type="checkbox" data-type="school"> school
      </li>
    </ul>
    <button id="find-places">Find Places</button>
  </div>

  <script src="map.js"></script>
</body>
</html>

Breaking it down. We include the stylesheet in the page:

1
<link rel="stylesheet" href="style.css">

Then we include jQuery and the Google Maps JavaScript library. Be sure to update the code so it uses your Google API Key:

1
2
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
  <script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=YOUR_GOOGLE_API_KEY&sensor=false&libraries=places"></script>

Next is the map container where we have map-canvas that will serve as the element where the map will be created. And the search box where the user will search for the place that will be used as a reference point:

1
2
3
4
<div id="map-container">
    <input type="text" id="search">
    <div id="map-canvas"></div>
  </div>

And then the type of places that we can find. Note that this isn’t everything we can find in Google Places API. I just picked some of the places that I think are essential. For a more complete list you can check this page. Here we added the data-type attribute which represents the place type. And then after the list we have the ‘Find Places’ button which basically just triggers the search:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<div id="place-types">
  <ul>
    <li>
      <input type="checkbox" data-type="bar"> bar
    </li>
    <li>
      <input type="checkbox" data-type="bus_station"> bus station
    </li>
    <li>
      <input type="checkbox" data-type="hospital"> hospital
    </li>
    <li>
      <input type="checkbox" data-type="health"> health
    </li>
    <li>
      <input type="checkbox" data-type="police"> police
    </li>
    <li>
      <input type="checkbox" data-type="post_office"> post office
    </li>
    <li>
      <input type="checkbox" data-type="store"> store
    </li>
    <li>
      <input type="checkbox" data-type="library"> library
    </li>
    <li>
      <input type="checkbox" data-type="fire_station"> fire station
    </li>
    <li>
      <input type="checkbox" data-type="gas_station"> gas station
    </li>
    <li>
      <input type="checkbox" data-type="convenience_store"> convenience store
    </li>
    <li>
      <input type="checkbox" data-type="school"> school
    </li>
  </ul>
  <button id="find-places">Find Places</button>
</div>

And then lastly we include the map.js file which will make this all work:

1
<script src="map.js"></script>

Next create the style.css file and put the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#map-container {
  float: left;
}

#map-canvas {
  height: 500px;
  width: 1000px;
}

#place-types {
    float: left;
}

#place-types ul li {
    list-style: none;
}

Finally we move on to the map.js file. First declare the default coordinate of the place that the map will display:

1
2
3
var lat = 18.35827827454; //default latitude
var lng = 121.63744354248; //default longitude
var home_coordinates = new google.maps.LatLng(lat, lng); //set default coordinates

Next, assign it to the map:

1
2
3
4
5
var map_options = {
  center: new google.maps.LatLng(lat, lng), //set map center
  zoom: 17, //set zoom level to 17
  mapTypeId: google.maps.MapTypeId.ROADMAP //set map type to road map
};

Next we set the search box as an auto-complete element. This will allow the user to see suggestions of matching locations as he types in the search box. We also need to bind it to the map so the auto-complete bounds are driven by the current viewport of the map.

1
2
3
var input = document.getElementById('search'); //get element to use as input for autocomplete
var autocomplete = new google.maps.places.Autocomplete(input); //set it as the input for autocomplete
autocomplete.bindTo('bounds', map); //bind auto-complete object to the map

Next we listen for the place_changed event that is triggered from the search box. If this event happens then we get the place information using the getPlace method available on the auto-complete object. This allows us to check if the place being searched is within the current map viewport. If it is then we just call the fitBounds method on the map object and pass in the geometry.viewport attribute from the place object. This sets the map center to the coordinates of the location. If its not within the current viewport then we call the setCenter method in the map object and pass in the geometry.location attribute in the place object. We also call the setZoom method in the map to ensure we still got the same zoom level. Lastly we set the position of the home_marker to the geometry.location in the place object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//executed when a place is selected from the search field
google.maps.event.addListener(autocomplete, 'place_changed', function(){

    //get information about the selected place in the autocomplete text field
    var place = autocomplete.getPlace();

    if (place.geometry.viewport){ //for places within the default view port (continents, countries)
      map.fitBounds(place.geometry.viewport); //set map center to the coordinates of the location
    } else { //for places that are not on the default view port (cities, streets)
      map.setCenter(place.geometry.location);  //set map center to the coordinates of the location
      map.setZoom(17); //set a custom zoom level of 17
    }

    home_marker.setMap(map); //set the map to be used by the  marker
    home_marker.setPosition(place.geometry.location); //plot marker into the coordinates of the location

});

Next we declare an array that will store the markers for the places that will be searched. Don’t confuse this with the place used as the reference point, the home_marker is used for this. The places I’m referring to are the place types such as grocery, church, etc. For convenience I’ll be referring to those markers as place type markers.

1
var markers_array = [];

Next create the method that would remove the place type markers from the map. We would need to call this every time the user clicks on the ‘Find Places’ button so that the previous search results will be removed from the map.

1
2
3
4
5
function removeMarkers(){
  for(i = 0; i < markers_array.length; i++){
    markers_array[i].setMap(null);
  }
}

Finally we have the method that listens for the click event on the ‘Find Places’ button. The first thing it does is to get the coordinates of the home_marker. This represents the coordinates of the reference point. After that, we declare an empty array, this is where we will store the place types selected by the user. We do that by looping through all the place types selected by the user and then we push the value for their data-type attribute in the array. Next we call the removeMarkers method to remove the place types markers that are currently plotted on the map. Next we make a POST request to the server and then passing in the coordinates of the reference point and the place types array. Once we get a response, we call the JSON.parse method so we can extract the results from the response. From there we loop through all the results and get the coordinates for each and then we plot the marker into the map. After that we assign an infowindow to each of the markers to that when its clicked it shows the name of the place.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
$('#find-places').click(function(){

  var lat = home_marker.getPosition().lat();
  var lng = home_marker.getPosition().lng();

  var place_types = [];

  //loop through all the place types that has been checked and push it to the place_types array
  $('#place-types input:checked').each(function(){
    var type = $(this).data('type');
    place_types.push(type);
  });

  removeMarkers(); //remove the current place type markers from the map

  //make a request to the server for the matching places
  $.post(
    'places.php',
    {
      'lat': lat,
      'lng': lng,
      'place_types': place_types
    },
    function(response){

      var response_data = JSON.parse(response);

      if(response_data.results){
        var results = response_data.results;
        var result_count = results.length;

        for(var x = 0; x < result_count; x++){

          //get coordinates of the place
          var lat = results[x]['geometry']['location']['lat'];
          var lng = results[x]['geometry']['location']['lng'];

          //create a new infowindow
          var infowindow = new google.maps.InfoWindow();

          //plot the marker into the map
          marker = new google.maps.Marker({
            position: new google.maps.LatLng(lat, lng),
            map: map,
            icon: results[x]['icon']
          });

          markers_array.push(marker);

          //assign an infowindow to the marker so that when its clicked it shows the name of the place
          google.maps.event.addListener(marker, 'click', (function(marker, x){
            return function(){
              infowindow.setContent("<div class='no-scroll'><strong>" + results[x]['name'] + "</strong><br>" + results[x]['vicinity'] + "</div>");
              infowindow.open(map, marker);
            }
          })(marker, x));


        }
      }

    }
  );

});

Here’s a screenshot of the final output:

google places

Conclusion

That’s it! In this tutorial you’ve learned how to work with the Google Place API in PHP. We have also create a simple app that would allow users to search specific types of places that is near the location used as a reference point. If you want to learn more, be sure to check out the resources below.

Resources

Comments