Get directions to nearest marker maps javascript API

I am trying to get the nearest marker to the user location and then get directions on button click, I have passed the markers to getDirections(markers) but when the function google.maps.geometry.spherical.computeDistanceBetween takes the google.maps.LatLng object throws the error Uncaught TypeError: Cannot read property 'lat' of undefined

But the markers array and the userLocation are both OK with the data (not undefined) so I can't understand what is going on.

The code:

jQuery(document).ready(function () {
  // Create the script tag, set the appropriate attributes
  
  let script = document.createElement('script');
  script.src = 'https://maps.googleapis.com/maps/api/js?key=AIzaSyBMCq6Fj4pN0Ku5ScVza28FZw0beM&callback=initMap&libraries=places&libraries=geometry';
  script.defer = true;
  var map
  let infowindow

  window.initMap = function () {
    const center = {
      lat: -36.561551,
      lng: -72.0954877
    }
    infowindow = new google.maps.InfoWindow();
    map = new google.maps.Map(document.getElementById('map'), {
      zoom: 5,
      center: center
    });
    let markers = setMarkers(map)
    getDirections(markers)

  }
  const locations = [
    ['Super Pellet Santiago', -33.458717664930084, -70.77513497336462],
    ['Super Pellet Chillan', -36.561551, -72.0954877],
    ['Super Pellet Concepción', -36.8158124, -73.0741686],
    ['Super Pellet Los Angeles', -37.4774907, -72.3245759],
    ['Super Pellet Angol', -33.80010128657071, 151.28747820854187],
    ['Super Pellet Temuco', -38.7702088, -72.6301967]
  ];
  function setMarkers(map) {
    let markers = []
    for (let i = 0; i < locations.length; i++) {
      markers[i] = new google.maps.Marker({
        title: locations[i][0],
        position: {
          lat: locations[i][1],
          lng: locations[i][2]
        },
        map: map
      });
      google.maps.event.addListener(markers, 'click', (function (markers, i) {
        return function () {
          infowindow.setContent(locations[i][0]);
          infowindow.open(map, markers);
        }
      })(markers, i));

    }
    return markers
    // Append the 'script' element to 'head'
  }
  document.head.appendChild(script);

  function getDirections(markers) {
    let userLocation
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(success,error)
      function success(position){
        userLocation = {
          lat: position.coords.latitude,
          lng: position.coords.longitude
        }
      }
      function error(){
        alert("Debes activar la geolocalización")
      }
    }
    //Get directions to nearest marker

    jQuery('#FINDPOS').click(() => {
      if(typeof(userLocation) === 'undefined'){
        alert("Debes permitir la localización")
      }
      else{
          let uLocation = new google.maps.LatLng(userLocation.lat,userLocation.lng)
          let distances = [];
          let closest = -1;
          if(markers.length > 0){
          for (i = 0; i < markers.length; i++) {
            var d = google.maps.geometry.spherical.computeDistanceBetween(markers[i].position, uLocation.position);
            distances[i] = d;
            if (closest == -1 || d < distances[closest]) {
              closest = i;
            }
          }
          alert('Closest marker is: ' + markers[closest].getTitle());
      }
    }
    })
  }
})

Upvotes: 0

Views: 202

Answers (1)

geocodezip
geocodezip

Reputation: 161334

Your uLocation variable is a google.maps.LatLng object, it doesn't have a .position property (for that matter, the .position property of google.maps.Marker objects isn't documented, it would be safer to call the (documented) .getPosition() method on the markers)

var d = google.maps.geometry.spherical.computeDistanceBetween(
          markers[i].position, uLocation.position);         

should be:

var d = google.maps.geometry.spherical.computeDistanceBetween(
          markers[i].getPosition(), uLocation);

related questions:

proof of concept fiddle

screenshot of map with closest marker result

code snippet:

jQuery(document).ready(function() {
  // Create the script tag, set the appropriate attributes

  let script = document.createElement('script');
  script.src = 'https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap&libraries=places&libraries=geometry';
  script.defer = true;
  var map
  let infowindow

  window.initMap = function() {

    const directionsRenderer = new google.maps.DirectionsRenderer();
    const center = {
      lat: -36.561551,
      lng: -72.0954877
    }
    infowindow = new google.maps.InfoWindow();
    map = new google.maps.Map(document.getElementById('map'), {
      zoom: 5,
      center: center
    });
    let markers = setMarkers(map)
    directionsRenderer.setMap(map);
    getDirections(markers, directionsRenderer)

  }
  const locations = [
    ['Super Pellet Santiago', -33.458717664930084, -70.77513497336462],
    ['Super Pellet Chillan', -36.561551, -72.0954877],
    ['Super Pellet Concepción', -36.8158124, -73.0741686],
    ['Super Pellet Los Angeles', -37.4774907, -72.3245759],
    ['Super Pellet Angol', -33.80010128657071, 151.28747820854187],
    ['Super Pellet Temuco', -38.7702088, -72.6301967]
  ];

  function setMarkers(map) {
    let markers = []
    for (let i = 0; i < locations.length; i++) {
      markers[i] = new google.maps.Marker({
        title: locations[i][0],
        position: {
          lat: locations[i][1],
          lng: locations[i][2]
        },
        map: map
      });
      google.maps.event.addListener(markers, 'click', (function(markers, i) {
        return function() {
          infowindow.setContent(locations[i][0]);
          infowindow.open(map, markers);
        }
      })(markers, i));

    }
    return markers
    // Append the 'script' element to 'head'
  }
  document.head.appendChild(script);

  function getDirections(markers, directionsRenderer) {
    let userLocation = {
      lat: -32.8894587,
      lng: -68.8458386
    }; // Mendoza, Capital Department, Mendoza Province, Argentina (-32.8894587, -68.8458386)
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(success, error)

      function success(position) {
        userLocation = {
          lat: position.coords.latitude,
          lng: position.coords.longitude
        }
      }

      function error() {
        document.getElementById('output').innerHTML = "Debes activar la geolocalización<br>defaulting to:Mendoza, Capital Department, Mendoza Province, Argentina (-32.8894587, -68.8458386)";
      }
    }
    //Get directions to nearest marker

    jQuery('#FINDPOS').click(() => {
      if (userLocation === 'undefined') {
        alert("Debes permitir la localización")
      } else {
        let uLocation = new google.maps.LatLng(userLocation.lat, userLocation.lng);
        let distances = [];
        let closest = -1;
        if (markers.length > 0) {
          for (i = 0; i < markers.length; i++) {
            var d = google.maps.geometry.spherical.computeDistanceBetween(markers[i].getPosition(), uLocation);
            distances[i] = d;
            if (closest == -1 || d < distances[closest]) {
              closest = i;
            }
          }
          document.getElementById('output').innerHTML = 'Closest marker is: ' + markers[closest].getTitle();
          calculateAndDisplayRoute(uLocation, markers[closest].getPosition(), directionsRenderer);
        }
      }
    })
  }
})

function calculateAndDisplayRoute(start, end, directionsRenderer) {
  const directionsService = new google.maps.DirectionsService();
  directionsService.route({
      origin: start,
      destination: end,
      travelMode: google.maps.TravelMode.DRIVING,
    },
    (response, status) => {
      if (status === "OK") {
        directionsRenderer.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: 90%;
}


/* Optional: Makes the sample page fill the window. */

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>

<head>
  <title>Simple Map</title>
  <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
  <!-- jsFiddle will insert css and js -->
</head>

<body>
  <input id="FINDPOS" value="FINDPOS" type="button" />
  <div id="output"></div>
  <div id="map"></div>
</body>

</html>

Upvotes: 1

Related Questions