-2

I have created a map solution, which locates the nearest teacher by distance and the travel time by public transport. But i have an issue looping trough the function that calculates the travel duration (calculateDuration();). Im not recieving any errors, but it returns "undefined".

How my script is set up:

/* 
Json i passed through the API ex.:

{
"status": "success",
"message": "Data selected from database",
"data": [
{
"id": "962",
"status": "Active",
"name": "Name name",
"lat": "55.690606",
"lng": "12.565927",
"subjects": "Subjects....",
"study": "Matematik, Københavns Universitet"
},
*/

(function() {
 window.onload = function() {
  // Setting up vars
  var json = $.getJSON('/api/v1/teachers_by_location', function(data) { 
  var out = data.data; 
  var map = new google.maps.Map(document.getElementById("map"), {
          center: new google.maps.LatLng(55.6764184, 12.569247200000063),
          zoom: 13,
          mapTypeId: google.maps.MapTypeId.ROADMAP
        });
  var infoWindow = new google.maps.InfoWindow();
   var distanceObj = [], i = 0;
  var directionsDisplay = new google.maps.DirectionsRenderer({map:map});
  var directionsService = new google.maps.DirectionsService;

  // Student marker
  latLng = new google.maps.LatLng(55.6764184, 12.569247200000063);
  var marker = new google.maps.Marker({
   position: latLng,
   map: map,
   animation: google.maps.Animation.BOUNCE,
   title: "Customer"
  });

     $.each(out, function (a, b) {
   distanceObj[i] = { distance: calculateDistance(55.6764184, 12.569247200000063, b.lng, b.lat), duration: calculateDuration(directionsService, b.lng, b.lat), location: a, name: b.name, subjects: b.subjects, study: b.study };
         ++i;
     });

     distanceObj.sort(function (a, b) {
         return parseInt(a.distance) - parseInt(b.distance)
     });

     $.each(distanceObj, function (a, b) {
      $('#list').append('<tr><td>' + b.name + '</td><td>' + b.study + '</td><td>' + b.subjects + '</td><td>' + b.distance + 'm (' + b.duration + ')</td></tr>');
     });

     function calculateDistance(meineLongitude, meineLatitude, long1, lat1) {
         erdRadius = 6371;
         meineLongitude = meineLongitude * (Math.PI / 180);
         meineLatitude = meineLatitude * (Math.PI / 180);
         long1 = long1 * (Math.PI / 180);
         lat1 = lat1 * (Math.PI / 180);
         x0 = meineLongitude * erdRadius * Math.cos(meineLatitude);
         y0 = meineLatitude * erdRadius;
         x1 = long1 * erdRadius * Math.cos(lat1);
         y1 = lat1 * erdRadius;
         dx = x0 - x1;
         dy = y0 - y1;
         d = Math.sqrt((dx * dx) + (dy * dy));
         return Math.round(d * 1000);
     };

  function calculateDuration(directionsService, long2, lat2) {
  var lat3 = parseFloat(lat2);
  var long3 = parseFloat(long2);

    directionsService.route({
      origin: {lat: lat3, lng: long3},
      destination: {lat: <?php echo $lat; ?>, lng: <?php echo $lng; ?>},
      travelMode: google.maps.TravelMode['TRANSIT']
    }, function(response, status) {
      if (status == google.maps.DirectionsStatus.OK) {
        return response.routes[0].legs[0].duration.text;
      } else {
        return "Error";
      }
    });
  };

  // Looping through the JSON data
  for (var i = 0, length = out.length; i < length; i++) {
   var data = out[i],
   latLng = new google.maps.LatLng(data.lat, data.lng);
   // Creating a marker and putting it on the map
   var marker = new google.maps.Marker({
    position: latLng,
    map: map,
    title: data.name
   });
   // Creating a closure to retain the correct data, notice how I pass the current data in the loop into the closure (marker, data)
   (function(marker, data) {
    // Attaching a click event to the current marker
    google.maps.event.addListener(marker, "click", function(e) {
     infoWindow.setContent(data.name);
     infoWindow.open(map, marker);
    });
   })(marker, data);
  }


  });
 }
})();
  body {
   font-family: helvetica;
  }
  #map { 
   position: absolute;
   right: 0;
   top: 0;
   width: 30%;
   height: 100%; 
  }
  #list_holder { 
   position: absolute;
   left: 0;
   bottom: 0;
   width: 70%;
   height: 100%; 
   overflow-y: scroll;
  }
  #list { 
   position: relative;
   float: left;
   width: 100%;
   height: 100%; 
  }
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="http://code.jquery.com/jquery-2.1.4.min.js//maps.googleapis.com/maps/api/js?sensor=false"></script>
 <div id="map"></div>
 <div id="list_holder">
  <table id="list" border="1">
   <tr>
    <td colspan="4">Nærmeste undervisere:</td>
   </tr>
  </table>
 </div>

Can anybody help me?

UPDATE: When modifying the script like so:

    function calculateDuration(directionsService, long2, lat2) {
    var lat3 = parseFloat(lat2);
    var long3 = parseFloat(long2);

      directionsService.route({
        origin: {lat: lat3, lng: long3},
        destination: {lat: <?php echo $lat; ?>, lng: <?php echo $lng; ?>},
        travelMode: google.maps.TravelMode['TRANSIT']
      }, function(response, status) {
        if (status == google.maps.DirectionsStatus.OK) {
          //return response.routes[0].legs[0].duration.text;
          //console.log("hej");
          console.log(response.routes[0].legs[0].duration.text);
        } else {
          //return "Error";
          console.log("error");
        }
      });
    };

It console.logs:

121 error 3 timer 49 min. 3 timer 14 min. 3 timer 32 min. 3 timer 21 min. 3 timer 48 min. 3 timer 20 min. 3 timer 21 min. 3 timer 16 min. 3 timer 18 min. 58 min.

So why the undefined when i try to return the text?

  • The DirectionsService is asynchronous, you can't return anything from its callback function, you have to use the data when/where it is available (inside the callback function) – geocodezip Aug 19 '15 at 12:40
  • Could you give me an example to work with geocodezip? :) – Mikkel Emil Lindblom Aug 19 '15 at 12:55
  • There are lots of duplicates available in SO (if not you exact question, then the same problem). Possible duplicate of [How to return the response from an asynchronous call?](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call) – geocodezip Aug 19 '15 at 13:15

1 Answers1

0

As stated in Directions Service docs:

  • duration indicates the total duration of this leg, as a Duration object of the following form:
    • value indicates the duration in seconds.
    • text contains a string representation of the duration.

These fields may be undefined if the duration is unknown.

As you got google.maps.DirectionsStatus.OK, your DirectionsResult is fine, try to use some parts of it that are not undefined :). console.log(JSON.stringify(response)); will help you to see which ones.

Ivan Jovović
  • 5,238
  • 3
  • 29
  • 57