Directions widget - load route with waypoints

1740
2
09-13-2016 01:11 PM
AndyWhitaker1
New Contributor III

In the JS API 3.17, I am using the Directions widget for routing.  After getting directions, I am saving the stops to a SQL Server database in JSON format as returned in the directions.  I can load the first two stops to the directions widget by calling updateStop(...).  If I've got more than 2 stops, then calling addStop(...) will add another stop in the widget.  What I cannot figure out is how to load a start and end point (two stops in the directions widget) AND a waypoint, then allow the directions widget to recalculate directions via a call to getDirections().  The waypoint is not a stop-over point.  It's just the location to pass through.  I found that the feature property in each stop has an attribute for "isWaypoint".  I have tried checking each stop and if isWaypoint==true, then do not add the stop to the directions widget.  However, the call to network analyst Route/solve should still have the waypoint(s) so the route is calculated through those points.  I'm really just trying to replicate a route with waypoints programmatically.  Below is some code I've been playing with to load the stops from the database.  routeData is my own Object with properties that I fill from the database.  The StopsJson property has the JSON for each exactly as found in the directions widget.  Anyone done this or have any advice?  If I have not been clear, please comment below and I can elaborate.

loadStops: function (routeData) {
   if (routeData != null &&
   routeData.Stops != null &&
   routeData.Stops.length > 0) {
   var stops = JSON.parse(routeData.StopsJson);
   if (stops == null) {
      return;
   }
   var numStops = stops.length;
   var comments = routeData.Comments.join(". ");
   var numWaypoints = 0;
   var insertionIndex = 0;
   // NOTE: do we call Route?solve directly?
   //this.map.directions.stops = stops;
   for (var index = 0; index < numStops; index++) {
      var stop = stops[index];
      var point = new Point(stop.feature.geometry);
      if (stop.feature.attributes.isWaypoint) { //(stop.name != "DWWP") {
         // This is a waypoint      

         //insertionIndex = index;
         numWaypoints++;
         // The following line adds the stop (as waypoint) but  DOESN'T WORK with directions widget

         //this.map.directions.stops.splice(insertionIndex, 0, stop);
      }
      else {
         insertionIndex = index - numWaypoints;
         if (insertionIndex < 2) {
            this.map.directions.updateStop(point, insertionIndex);
         }
         else {
            this.map.directions.addStop(point, insertionIndex);
         }
      }
}


}
},

0 Kudos
2 Replies
AndyWhitaker1
New Contributor III

So I've got a solution that allows me to load a route that has waypoints.  A couple of notes.  

1) I had to add the stops as points and allow the directions widget to make a call to reverse geocode each point.

2) I had to add my actual stops (not waypoints) first then call getDirections() without the waypoints.  In my case, routes will have a start and end point with (potentially) waypoints in between to force a route to take certain roads.

3) after getDirections() returns, then add the waypoints as stops.

4) I had to track the index for each waypoint, then coerce the waypoints in my event handler for the directions-start event and set the isWaypoint bool flag to true.

With these caveats, it seemed to work...most of the time.  I haven't identified exactly why, but I believe the incremental solving of the route (meaning it solves the route for each stop, then moves on to the next stop), that sometime there existed a race condition between solving the route and updating the stops in the UI for the directions widget.  My current workaround, though not great, was to center and zoom to the route's extent prior to loading all the stops.  This seems to take just enough time to make it all work.  Here's some code (that is still experimental and in development):

loadStops: function (routeData) {
if (routeData != null &&
routeData.Stops != null &&
routeData.Stops.length > 0) {
var stops = JSON.parse(routeData.StopsJson);
if (stops == null) {
   return;
}
var numStops = stops.length;
var numWaypoints = 0;
this.map.directions.stopsAsWaypoints = [];

var waypoints = [];

// zoom to avoid race condition? between rest api solve and directions widget
var geo = JSON.parse(routeData.Geometry);
var route = {
   geometry: geo,
   "symbol": { "color": [0, 0, 0, 255], "width": 5, "type": "esriSLS", "style": "esriSLSSolid" }
};
var routeGraphic = new Graphic(route);
var graphics = [];
graphics[0] = routeGraphic;
var graphicextent = esri.graphicsExtent(graphics);
this.map.setExtent(graphicextent, true);

// Add stops (not waypoints), one at a time.

// Keep waypoints in array to add when directions have finished

for (var index = 0; index < numStops; index++) {
   var stop = stops[index];
   var point = new Point(stop.feature.geometry);
   points[index] = point;
   if (stop.feature.attributes.isWaypoint) {
      this.map.directions.stopsAsWaypoints[numWaypoints] = index;
      waypoints[numWaypoints] = point;//stop;
      numWaypoints++;
   }
   else
   {
      this.map.directions.addStop(point, index);
   }
}

this.map.directions.getDirections().then(lang.hitch(this, function () {
   // NOTE: There appears to be a race condition here where directions are recalculated
   // if place a breakpoint in directionsstart it works
   this.map.directions.addStops(waypoints, this.map.directions.stopsAsWaypoints[0]);
}));
}
}

Here's part of the directions-start event handler:

directionsStartHandler: function (event) {
console.log("Starting directions...");

if (this.embeddedDirections.stops && this.embeddedDirections.stops.length > 2 &&
      this.embeddedDirections.stopsAsWaypoints) {
      for (var ctr = 0; ctr < this.embeddedDirections.stops.length; ctr++) {

         // use jQuery $.inArray to see if this stop is in the waypoint list
         if ($.inArray(ctr, this.embeddedDirections.stopsAsWaypoints) != -1) {
            this.embeddedDirections.stops[ctr].feature.attributes.isWaypoint = true;
            console.log("Waypoint: " + JSON.stringify(this.embeddedDirections.stops[ctr]));
         }
      }
}

benchikh
New Contributor III

Hi, I know it is an old question!

Could you please share with me your code or more details about the issue.

I am working with directions widget argis api 3.38, and I have to save the data route details on a sqlserver and try to load it again on the map.

So could you please share with me the details please ? 

 

 

 

0 Kudos