Using the directions service with SearchBox Google Maps API?

1

I'm working on a project with the Google Maps API, I've been guiding myself with this Example that gives the same page of the API " Place Autocomplete and Directions "

Try to do mine by guiding me by example, replacing class Autocomplete with class SearchBox but I could not achieve anything ....

Here is the code I was doing, add two search boxes that work with the class SearchBox but I do not know how to correctly implement the indications service so that it works like the previous example that has the class Autocomplete .

If you could give me an example of how to implement that service in the code I try to do, I would appreciate it a lot.

function initAutocomplete() {
    var map = new google.maps.Map(document.getElementById('map'), {
      center: {lat: -33.8688, lng: 151.2195},
      zoom: 13,
      mapTypeId: 'roadmap'
    });

    // Create the search box and link it to the UI element.
    var input = document.getElementById('pac-input');
    var input2 = document.getElementById('pac-input2');
    var searchBox = new google.maps.places.SearchBox(input);
    var searchBox2 = new google.maps.places.SearchBox(input2);
    map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
    map.controls[google.maps.ControlPosition.TOP_LEFT].push(input2);

    // Bias the SearchBox results towards current map's viewport.
    map.addListener('bounds_changed', function() {
      searchBox.setBounds(map.getBounds());
      searchBox2.setBounds(map.getBounds());
    });

    var markers = [];
    // Listen for the event fired when the user selects a prediction and retrieve
    // more details for that place.
    searchBox.addListener('places_changed', function() {
      var places = searchBox.getPlaces();

      if (places.length == 0) {
        return;
      }

      // Clear out the old markers.
      markers.forEach(function(marker) {
        marker.setMap(null);
      });
      markers = [];

      // For each place, get the icon, name and location.
      var bounds = new google.maps.LatLngBounds();
      places.forEach(function(place) {
        if (!place.geometry) {
          console.log("Returned place contains no geometry");
          return;
        }
        var icon = {
          url: place.icon,
          size: new google.maps.Size(71, 71),
          origin: new google.maps.Point(0, 0),
          anchor: new google.maps.Point(17, 34),
          scaledSize: new google.maps.Size(25, 25)
        };

        // Create a marker for each place.
        markers.push(new google.maps.Marker({
          map: map,
          icon: icon,
          title: place.name,
          position: place.geometry.location
        }));

        if (place.geometry.viewport) {
          // Only geocodes have viewport.
          bounds.union(place.geometry.viewport);
        } else {
          bounds.extend(place.geometry.location);
        }
      });
      map.fitBounds(bounds);
    });
  }


var markers2 = [];
// Listen for the event fired when the user selects a prediction and retrieve
// more details for that place.
searchBox2.addListener('places_changed', function() {
  var places2 = searchBox2.getPlaces();

  if (places.length == 0) {
    return;
  }

  // Clear out the old markers.
  markers2.forEach(function(marker) {
    marker2.setMap(null);
  });
  markers2 = [];

  // For each place, get the icon, name and location.
  var bounds = new google.maps.LatLngBounds();
  places.forEach(function(place) {
    if (!place.geometry) {
      console.log("Returned place contains no geometry");
      return;
    }
    var icon = {
      url: place.icon,
      size: new google.maps.Size(71, 71),
      origin: new google.maps.Point(0, 0),
      anchor: new google.maps.Point(17, 34),
      scaledSize: new google.maps.Size(25, 25)
    };

    // Create a marker for each place.
    markers2.push(new google.maps.Marker({
      map: map,
      icon: icon,
      title: place.name,
      position: place.geometry.location
    }));

    if (place.geometry.viewport) {
      // Only geocodes have viewport.
      bounds.union(place.geometry.viewport);
    } else {
      bounds.extend(place.geometry.location);
    }
  });
  map.fitBounds(bounds);
});
#map {
        height: 100%;
      }
      /* Optional: Makes the sample page fill the window. */
      html, body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
       .controls {
        margin-top: 10px;
        border: 1px solid transparent;
        border-radius: 2px 0 0 2px;
        box-sizing: border-box;
        -moz-box-sizing: border-box;
        height: 32px;
        outline: none;
        box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
      }

      #pac-input,
      #pac-input2 {
        background-color: #fff;
        font-family: Roboto;
        font-size: 15px;
        font-weight: 300;
        margin-left: 12px;
        padding: 0 11px 0 13px;
        text-overflow: ellipsis;
        width: 300px;
      }

      #pac-input:focus,
      #pac-input2:focus {
        border-color: #4d90fe;
      }

      .pac-container {
        font-family: Roboto;
      }

      #type-selector {
        color: #fff;
        background-color: #4d90fe;
        padding: 5px 11px 0px 11px;
      }

      #type-selector label {
        font-family: Roboto;
        font-size: 13px;
        font-weight: 300;
      }
      #target {
        width: 345px;
      }
<input id="pac-input" class="controls center" type="text center" placeholder="Inicio">
  <input id="pac-input2" class="controls center" type="text center" placeholder="Fin">
    <div id="map"></div>
    
    
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDcglr0mL358bvGoBXuKhftNS1MBz76Zhg&libraries=places&callback=initMap"
    async defer></script>
    
asked by Rodolfo Zamora Lopez 26.04.2017 в 09:06
source

1 answer

2

Short answer

Unlike Autocomplete , SearchBox can return one or several results. What you need to do is pass a single result to the address service.

Example 1

As for an example of the use of SearchBox, in Places search box (in Spanish), an "official" example is included. In this, two "subroutines" are included, one for the case that a single result has been obtained, in which the value returned is a scale , and another for the case of multiple results, in which the value returned is a matrix.

Next I include the adaptation of the code of the previous reference. The adaptation is to ensure that the location of a result is always shown. For this, in the subroutine that handles the case in which the result of SearchBox is a matrix, forEach was replaced by some including at the end of the statement return true , so that it is only executed for the first result, this, in order to perform a minimum adaptation in turn for demonstration purposes.

  

Notes:

     
  • The Google Maps API key was borrowed from the original question from the OP.
  •   
  • The center of the map was changed, for "mere local pride":)
  •   

    Instructions to try

    Note: It is recommended to try using the extended option

  • Press the "Execute" button
  • Test the following cases:
  • Case "autocomplete"

    Write pizza and select one of the suggestions with the marker icon

    Case "search"

    Type pizza and press Enter .

    Code

    // This example adds a search box to a map, using the Google Place Autocomplete
    // feature. People can enter geographical searches. The search box will return a
    // pick list containing a mix of places and predicted search terms.
    
    // This example requires the Places library. Include the libraries=places
    // parameter when you first load the API. For example:
    // <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">
    
    function initAutocomplete() {
      var map = new google.maps.Map(document.getElementById('map'), {
        // Coordenadas de Monterrey, N.L., México
        center: {lat: 25.685088, lng:-100.327482}, //{lat: -33.8688, lng: 151.2195},
        zoom: 13,
        mapTypeId: 'roadmap'
      });
    
      // Create the search box and link it to the UI element.
      var input = document.getElementById('pac-input');
      var searchBox = new google.maps.places.SearchBox(input);
      map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
    
      // Bias the SearchBox results towards current map's viewport.
      map.addListener('bounds_changed', function() {
        searchBox.setBounds(map.getBounds());
      });
    
      var markers = [];
      // Listen for the event fired when the user selects a prediction and retrieve
      // more details for that place.
      searchBox.addListener('places_changed', function() {
        var places = searchBox.getPlaces();
    
        if (places.length == 0) {
          return;
        }
    
        // Clear out the old markers.
        markers.forEach(function(marker) {
          marker.setMap(null);
        });
        markers = [];
    
        // For each place, get the icon, name and location.
        var bounds = new google.maps.LatLngBounds();
        /*
         * Para fines de minimizar las adecuaciones debido a que es este una demostración de adaptación mínima de código, se reemplaza forEach por some.
         */ 
        // places.forEach(function(place) {
        places.some(function(place) {
          if (!place.geometry) {
            console.log("Returned place contains no geometry");
            return;
          }
          var icon = {
            url: place.icon,
            size: new google.maps.Size(71, 71),
            origin: new google.maps.Point(0, 0),
            anchor: new google.maps.Point(17, 34),
            scaledSize: new google.maps.Size(25, 25)
          };
    
          // Create a marker for each place.
          markers.push(new google.maps.Marker({
            map: map,
            icon: icon,
            title: place.name,
            position: place.geometry.location
          }));
    
          if (place.geometry.viewport) {
            // Only geocodes have viewport.
            bounds.union(place.geometry.viewport);
          } else {
            bounds.extend(place.geometry.location);
          }
          // some interrumpe su ejecución en cuanto devuelve un valor verdadero (true)
          return true;
        });
        map.fitBounds(bounds);
      });
    }
    /* Always set the map height explicitly to define the size of the div
     * element that contains the map. */
    #map {
      height: 100%;
    }
    /* Optional: Makes the sample page fill the window. */
    html, body {
      height: 100%;
      margin: 0;
      padding: 0;
    }
    .controls {
      margin-top: 10px;
      border: 1px solid transparent;
      border-radius: 2px 0 0 2px;
      box-sizing: border-box;
      -moz-box-sizing: border-box;
      height: 32px;
      outline: none;
      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
    }
    
    #pac-input {
      background-color: #fff;
      font-family: Roboto;
      font-size: 15px;
      font-weight: 300;
      margin-left: 12px;
      padding: 0 11px 0 13px;
      text-overflow: ellipsis;
      width: 300px;
    }
    
    #pac-input:focus {
      border-color: #4d90fe;
    }
    
    .pac-container {
      font-family: Roboto;
    }
    
    #type-selector {
      color: #fff;
      background-color: #4d90fe;
      padding: 5px 11px 0px 11px;
    }
    
    #type-selector label {
      font-family: Roboto;
      font-size: 13px;
      font-weight: 300;
    }
    #target {
      width: 345px;
    }
    <input id="pac-input" class="controls" type="text" placeholder="Search Box">
    <div id="map"></div>
    
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDcglr0mL358bvGoBXuKhftNS1MBz76Zhg&libraries=places&callback=initAutocomplete"
         async defer></script>

    Example 2

    I've taken the referred example by the OP and made the minimum of modifications. The premise was to avoid inserting new lines of code for which they were placed between /* and */ functions replace and then the replacement functions were written, basically changing Autocomplete by SearchBox and getPlace() by getPlaces()[0] . Note that in the second case the zero index is included in order to use the first "place".

    The modifications were like the following:

    • on the next line "replaced" Autocomplete by SearchBox

      var originAutocomplete = new google.maps.places/*.Autocomplete*/.SearchBox(
        originInput, {placeIdOnly: true});
      
    • on the next line "replaced" getPlace() by getPlaces[0]

      var place = autocomplete/*.getPlace()*/.getPlaces()[0];
      
      

    Notes:

         
  • The Google Maps API key was borrowed from the original question from the OP.
  •   
  • The center of the map was changed, for "mere local pride":)
  •   

    Instructions to try

    Note: It is recommended to try using the extended option

  • Press the "Execute" button
  • Test the following cases:
  • Case "autocomplete"

  • In the first box, type pizza and select one of the suggestions with the marker icon
  • In the second box, type museo and select one of the suggestions in the marker icon
  • Case "search"

  • Type pizza and press Enter and then Tab .
  • Write museo and press Enter .
  • Code

    // This example requires the Places library. Include the libraries=places
    // parameter when you first load the API. For example:
    // <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places">
    
    function initMap() {
      var map = new google.maps.Map(document.getElementById('map'), {
        mapTypeControl: false,
        center: {lat: 25.6810658, lng: -100.3317736},//{lat: 33.8688, lng: -151.2195},
        zoom: 13
      });
    
      new AutocompleteDirectionsHandler(map);
    }
    
     /**
      * @constructor
     */
    function AutocompleteDirectionsHandler(map) {
      this.map = map;
      this.originPlaceId = null;
      this.destinationPlaceId = null;
      this.travelMode = 'WALKING';
      var originInput = document.getElementById('origin-input');
      var destinationInput = document.getElementById('destination-input');
      var modeSelector = document.getElementById('mode-selector');
      this.directionsService = new google.maps.DirectionsService;
      this.directionsDisplay = new google.maps.DirectionsRenderer;
      this.directionsDisplay.setMap(map);
    
      var originAutocomplete = new google.maps.places/*.Autocomplete*/.SearchBox(
          originInput, {placeIdOnly: true});
      var destinationAutocomplete = new google.maps.places/*.Autocomplete*/.SearchBox(
          destinationInput, {placeIdOnly: true});
    
      this.setupClickListener('changemode-walking', 'WALKING');
      this.setupClickListener('changemode-transit', 'TRANSIT');
      this.setupClickListener('changemode-driving', 'DRIVING');
    
      this.setupPlaceChangedListener(originAutocomplete, 'ORIG');
      this.setupPlaceChangedListener(destinationAutocomplete, 'DEST');
    
      this.map.controls[google.maps.ControlPosition.TOP_LEFT].push(originInput);
      this.map.controls[google.maps.ControlPosition.TOP_LEFT].push(destinationInput);
      this.map.controls[google.maps.ControlPosition.TOP_LEFT].push(modeSelector);
    }
    
    // Sets a listener on a radio button to change the filter type on Places
    // Autocomplete.
    AutocompleteDirectionsHandler.prototype.setupClickListener = function(id, mode) {
      var radioButton = document.getElementById(id);
      var me = this;
      radioButton.addEventListener('click', function() {
        me.travelMode = mode;
        me.route();
      });
    };
    
    AutocompleteDirectionsHandler.prototype.setupPlaceChangedListener = function(autocomplete, mode) {
      var me = this;
      autocomplete.bindTo('bounds', this.map);
      autocomplete.addListener(/*'place_changed'*/'places_changed', function() {
        var place = autocomplete/*.getPlace()*/.getPlaces()[0];
        if (!place.place_id) {
          window.alert("Please select an option from the dropdown list.");
          return;
        }
        if (mode === 'ORIG') {
          me.originPlaceId = place.place_id;
        } else {
          me.destinationPlaceId = place.place_id;
        }
        me.route();
      });
    
    };
    
    
    AutocompleteDirectionsHandler.prototype.route = function() {
      if (!this.originPlaceId || !this.destinationPlaceId) {
        return;
      }
      var me = this;
    
      this.directionsService.route({
        origin: {'placeId': this.originPlaceId},
        destination: {'placeId': this.destinationPlaceId},
        travelMode: this.travelMode
      }, function(response, status) {
        if (status === 'OK') {
          me.directionsDisplay.setDirections(response);
        } else {
          window.alert('Directions request failed due to ' + status);
        }
      });
    };
    /* Always set the map height explicitly to define the size of the div
     * element that contains the map. */
    #map {
      height: 100%;
    }
    /* Optional: Makes the sample page fill the window. */
    html, body {
      height: 100%;
      margin: 0;
      padding: 0;
    }
    .controls {
      margin-top: 10px;
      border: 1px solid transparent;
      border-radius: 2px 0 0 2px;
      box-sizing: border-box;
      -moz-box-sizing: border-box;
      height: 32px;
      outline: none;
      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
    }
    
    #origin-input,
    #destination-input {
      background-color: #fff;
      font-family: Roboto;
      font-size: 15px;
      font-weight: 300;
      margin-left: 12px;
      padding: 0 11px 0 13px;
      text-overflow: ellipsis;
      width: 200px;
    }
    
    #origin-input:focus,
    #destination-input:focus {
      border-color: #4d90fe;
    }
    
    #mode-selector {
      color: #fff;
      background-color: #4d90fe;
      margin-left: 12px;
      padding: 5px 11px 0px 11px;
    }
    
    #mode-selector label {
      font-family: Roboto;
      font-size: 13px;
      font-weight: 300;
    }
    <input id="origin-input" class="controls" type="text"
        placeholder="Enter an origin location">
    
    <input id="destination-input" class="controls" type="text"
        placeholder="Enter a destination location">
    
    <div id="mode-selector" class="controls">
      <input type="radio" name="type" id="changemode-walking" checked="checked">
      <label for="changemode-walking">Walking</label>
    
      <input type="radio" name="type" id="changemode-transit">
      <label for="changemode-transit">Transit</label>
    
      <input type="radio" name="type" id="changemode-driving">
      <label for="changemode-driving">Driving</label>
    </div>
    
    <div id="map"></div>
    
    
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDcglr0mL358bvGoBXuKhftNS1MBz76Zhg&libraries=places&callback=initMap"
        async defer></script>
        
    answered by 26.04.2017 / 15:16
    source