Get driving directions sample customization

3778
15
05-17-2011 11:44 PM
AlexeyTereshenkov
Regular Contributor III
Hi all,

My aim is to create a web application where a user could click on the map or type in the address end and start points for the routing; the route will be calculated and shown on the map; the directions text will be shown on the html page to the user. This application I need exclusively for testing of the routing capabilities available via the ArcGIS Web API.

It seemed that the easiest way would be to customize the sample Get driving directions (http://resources.esri.com/help/9.3/arcgisserver/apis/javascript/arcgis/help/jssamples_start.htm#jssa...) to use European geocoding and routing services.

I have exchanged the locator and the routing services strings with the European services:

locator = new esri.tasks.Locator("http://tasks.arcgisonline.com/ArcGIS/rest/services/Locators/TA_Address_EU/GeocodeServer");


and

routeTask = new esri.tasks.RouteTask("http://tasks.arcgisonline.com/ArcGIS/rest/services/NetworkAnalysis/ESRI_Route_EU/NAServer/Route");


However, when trying to get the directions, I get the error message from the browser:

An error occured
Unable to complete  operation.
Required field '<i>Country</i>' must be specified


I understand that probably this coming from the code where the parsing of the input geocoding strings happen. I.e.

//Parse and geocode "from" address
        var fromArr = dojo.byId("fromTxf").value.split(","),
            fromAddress = { Address:fromArr[0], City:fromArr[1], State:fromArr[2], Zip:fromArr[3] };
        locator.addressToLocations(fromAddress, ["Loc_name"], function(addressCandidates) { configureRoute(addressCandidates, "from"); });

        //Parse and geocode "to" address
        var toArr = dojo.byId("toTxf").value.split(","),
            toAddress = { Address:toArr[0], City:toArr[1], State:toArr[2], Zip:toArr[3] };
        locator.addressToLocations(toAddress, ["Loc_name"], function(addressCandidates) { configureRoute(addressCandidates, "to"); });
      }


However, I am not sure how one is supposed to edit this piece of code (or maybe others, too!) in order to reflect the European geocoding parameters (I've looked a bit at http://tasks.arcgisonline.com/ArcGIS/rest/services/Locators/TA_Address_EU/GeocodeServer).

I would appreciate if anyone could give me some tips what shall I look at. Maybe it is easier to customize the Find Route sample (http://resources.esri.com/help/9.3/arcgisserver/apis/javascript/arcgis/help/jssamples_start.htm#jssa...) by implementing the routing directions there, but I am not that familiar with the JavaScript API.

Thank you.
0 Kudos
15 Replies
HemingZhu
Occasional Contributor III
Hi all,

My aim is to create a web application where a user could click on the map or type in the address end and start points for the routing; the route will be calculated and shown on the map; the directions text will be shown on the html page to the user. This application I need exclusively for testing of the routing capabilities available via the ArcGIS Web API.

It seemed that the easiest way would be to customize the sample Get driving directions (http://resources.esri.com/help/9.3/arcgisserver/apis/javascript/arcgis/help/jssamples_start.htm#jssa...) to use European geocoding and routing services.

I have exchanged the locator and the routing services strings with the European services:

locator = new esri.tasks.Locator("http://tasks.arcgisonline.com/ArcGIS/rest/services/Locators/TA_Address_EU/GeocodeServer");


and

routeTask = new esri.tasks.RouteTask("http://tasks.arcgisonline.com/ArcGIS/rest/services/NetworkAnalysis/ESRI_Route_EU/NAServer/Route");


However, when trying to get the directions, I get the error message from the browser:

An error occured
Unable to complete  operation.
Required field '<i>Country</i>' must be specified


I understand that probably this coming from the code where the parsing of the input geocoding strings happen. I.e.

//Parse and geocode "from" address
        var fromArr = dojo.byId("fromTxf").value.split(","),
            fromAddress = { Address:fromArr[0], City:fromArr[1], State:fromArr[2], Zip:fromArr[3] };
        locator.addressToLocations(fromAddress, ["Loc_name"], function(addressCandidates) { configureRoute(addressCandidates, "from"); });

        //Parse and geocode "to" address
        var toArr = dojo.byId("toTxf").value.split(","),
            toAddress = { Address:toArr[0], City:toArr[1], State:toArr[2], Zip:toArr[3] };
        locator.addressToLocations(toAddress, ["Loc_name"], function(addressCandidates) { configureRoute(addressCandidates, "to"); });
      }


However, I am not sure how one is supposed to edit this piece of code (or maybe others, too!) in order to reflect the European geocoding parameters (I've looked a bit at http://tasks.arcgisonline.com/ArcGIS/rest/services/Locators/TA_Address_EU/GeocodeServer).

I would appreciate if anyone could give me some tips what shall I look at. Maybe it is easier to customize the Find Route sample (http://resources.esri.com/help/9.3/arcgisserver/apis/javascript/arcgis/help/jssamples_start.htm#jssa...) by implementing the routing directions there, but I am not that familiar with the JavaScript API.

Thank you.


If you looked at http://tasks.arcgisonline.com/ArcGIS/rest/services/Locators/TA_Address_EU/GeocodeServer, among the Address Fields, Country is required. So when you defined your address parameter, you have to include country name. Othervise, you will get the error.

var address ={}; address.Country =must have a value;
0 Kudos
AlexeyTereshenkov
Regular Contributor III
Hi Heming,

Thanks for the reply! So, I have to paste this line of code somewhere in the page, right?

I have declared the variable address right after the creating an instance of the locator:

 locator = new esri.tasks.Locator("http://tasks.arcgisonline.com/ArcGIS/rest/services/Locators/TA_Address_EU/GeocodeServer");
        dojo.connect(locator, "onError", errorHandler);
  var address ={}; 
  address.Country = Sweden;  


Now I don't get this error that country is required, but there is still no route generated and of course there are no directions shown either. In the textboxes, I am typing a string like:
Street HouseNumber City Postcode Country

I guess the problem has something to do with the piece of code you gave me, I might have interpreted it incorrectly.

Thank you again for the help, Heming.
0 Kudos
HemingZhu
Occasional Contributor III
Hi Heming,

Thanks for the reply! So, I have to paste this line of code somewhere in the page, right?

I have declared the variable address right after the creating an instance of the locator:

 locator = new esri.tasks.Locator("http://tasks.arcgisonline.com/ArcGIS/rest/services/Locators/TA_Address_EU/GeocodeServer");
        dojo.connect(locator, "onError", errorHandler);
  var address ={}; 
  address.Country = Sweden;  


Now I don't get this error that country is required, but there is still no route generated and of course there are no directions shown either. In the textboxes, I am typing a string like:
Street HouseNumber City Postcode Country

I guess the problem has something to do with the piece of code you gave me, I might have interpreted it incorrectly.

Thank you again for the help, Heming.


The locator you use has 4 address fields: Address, City, Postcode, County. So your code should look like:
var address ={};
address.Address ="123 sesame street";
address.City ="heaven";
address.Postcode="12345";
address.Country = "Sweden";

The more detail you give, the better chance you will get a hit.
FYI. ArcGIS 10 allow you to put a single line of text like API stated:
var address = {"Single Line Input":"123 sesame street, heaven, 12345, Sweden "};
0 Kudos
AlexeyTereshenkov
Regular Contributor III
Hi Heming,

Thank you so much for the reply. Unfortunately, I was not able to make the script work. I still get the message the the Country is required.

Here is the bunch of code I've used:

   locator = new esri.tasks.Locator("http://tasks.arcgisonline.com/ArcGIS/rest/services/Locators/TA_Address_EU/GeocodeServer");
        dojo.connect(locator, "onError", errorHandler);
  
  var address ={};
  address.Address ="5 SomeNameStreet";
  address.City ="SomeCityName";
  address.Postcode="SomePostalcode";
  address.Country = "Sweden";


This is the only thing I have changed in the whole sample (plus geocoding and routing REST URLs). What do you think is missing then?
0 Kudos
AlexeyTereshenkov
Regular Contributor III
Hi Heming,

Thank you so much for the reply. Unfortunately, I was not able to make the script work. I still get the message that the Country is required.

Here is the bunch of code I've used:

   locator = new esri.tasks.Locator("http://tasks.arcgisonline.com/ArcGIS/rest/services/Locators/TA_Address_EU/GeocodeServer");
        dojo.connect(locator, "onError", errorHandler);
  
  var address ={};
  address.Address ="5 SomeNameStreet";
  address.City ="SomeCityName";
  address.Postcode="SomePostalcode";
  address.Country = "Sweden";


This is the only thing I have changed in the whole sample ( plus geocoding and routing REST URLs). What do you think is missing then?
0 Kudos
HemingZhu
Occasional Contributor III
The locator you use has 4 address fields: Address, City, Postcode, County. So your code should look like:
var address ={};
address.Address ="123 sesame street";
address.City ="heaven";
address.Postcode="12345";
address.Country = "Sweden";

The more detail you give, the better chance you will get a hit.
FYI. ArcGIS 10 allow you to put a single line of text like API stated:
var address = {"Single Line Input":"123 sesame street, heaven, 12345, Sweden "};


Test your input on http://tasks.arcgisonline.com/ArcGIS/rest/services/Locators/TA_Address_EU/GeocodeServer/findAddressC... to see whether your input is wrong or somewhere else in your code...
0 Kudos
AlexeyTereshenkov
Regular Contributor III
Hi Heming,

Thank you. I have tested the input and I have got several results, so it should be no problem in here. Any other suggestions?
0 Kudos
HemingZhu
Occasional Contributor III
Hi Heming,

Thank you. I have tested the input and I have got several results, so it should be no problem in here. Any other suggestions?


Then you might have to look into your code (i can take a look if you don't mind posting your code).
0 Kudos
AlexeyTereshenkov
Regular Contributor III
Heming,

That is very nice of you. The code is the exact copy of the sample page one can get from the Resource Center apart from the REST URL for the geocoding and routing services (now European) plus those address variable parameters you have helped me to declare.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=7,IE=9" />
   
 <!--The viewport meta tag is used to improve the presentation and behavior of the samples 
      on iOS devices-->
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
    <title>Directions</title>

    <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.3/js/dojo/dijit/themes/claro/claro.css">
    <script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=2.3"></script>

    <style type="text/css" media="screen">
      .segment { cursor:pointer; padding-top:3px; padding-bottom:3px; }
    </style>

    <script type="text/javascript">
      dojo.require("esri.map");
      dojo.require("esri.tasks.locator");
      dojo.require("esri.tasks.route");
      dojo.require("esri.utils");

      var map, locator, routeTask, routeParams, routes = [];
      var fromSymbol, toSymbol, routeSymbol, segmentSymbol;
      var from, to, directions, directionFeatures, segmentGraphic;

      function init() {
        esri.config.defaults.io.proxyUrl = "/proxy/proxy.ashx";

        map = new esri.Map("map", {
          extent: new esri.geometry.Extent({"xmin":-13279958,"ymin":3856610,"xmax":-12546163,"ymax":4345807,"spatialReference":{"wkid":102100}})
        });

        map.addLayer(new esri.layers.ArcGISTiledMapServiceLayer("http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"));

        locator = new esri.tasks.Locator("http://tasks.arcgisonline.com/ArcGIS/rest/services/Locators/TA_Address_EU/GeocodeServer");
        dojo.connect(locator, "onError", errorHandler);

// variable for the required address geocoding field
 var address ={}; 
  address.Address ="1 Kungsgatan";
  address.City ="Stockholm";
  address.Postcode="11143";
  address.Country = "Sweden";

        routeTask = new esri.tasks.RouteTask("http://tasks.arcgisonline.com/ArcGIS/rest/services/NetworkAnalysis/ESRI_Route_EU/NAServer/Route");
        routeParams = new esri.tasks.RouteParameters();
        routeParams.stops = new esri.tasks.FeatureSet();
        routeParams.returnRoutes = false;
        routeParams.returnDirections = true;
        routeParams.directionsLengthUnits = esri.Units.MILES;
        routeParams.outSpatialReference = new esri.SpatialReference({ wkid:102100 });

        dojo.connect(routeTask, "onSolveComplete", showRoute);
        dojo.connect(routeTask, "onError", errorHandler);

        //Configure symbols to be used for destinations and route segments
        fromSymbol = new esri.symbol.SimpleMarkerSymbol().setColor(new dojo.Color([0,255,0]));
        toSymbol = new esri.symbol.SimpleMarkerSymbol().setColor(new dojo.Color([255,0,0]));

        routeSymbol = new esri.symbol.SimpleLineSymbol().setColor(new dojo.Color([0,0,255,0.5])).setWidth(4);
        segmentSymbol = new esri.symbol.SimpleLineSymbol().setColor(new dojo.Color([255,0,0,0.5])).setWidth(8);
      }

      dojo.addOnLoad(init);

      function getDirections() {
        routeParams.stops.features = [];
        map.graphics.clear();
        segmentGraphic = null;

        //Parse and geocode "from" address
        var fromArr = dojo.byId("fromTxf").value.split(","),
            fromAddress = { Address:fromArr[0], City:fromArr[1], State:fromArr[2], Zip:fromArr[3] };
        locator.addressToLocations(fromAddress, ["Loc_name"], function(addressCandidates) { configureRoute(addressCandidates, "from"); });

        //Parse and geocode "to" address
        var toArr = dojo.byId("toTxf").value.split(","),
            toAddress = { Address:toArr[0], City:toArr[1], State:toArr[2], Zip:toArr[3] };
        locator.addressToLocations(toAddress, ["Loc_name"], function(addressCandidates) { configureRoute(addressCandidates, "to"); });
      }


      function configureRoute(addressCandidates, type) {
        var stop = null, score = 0;

        //Get the address match with the top score
        dojo.forEach(addressCandidates, function(candidate) {
          if (candidate.score > score && candidate.attributes.Loc_name === "US_RoofTop") {
            stop = candidate;
            score = candidate.score;
          }
        });
        
        //convert the locations to web mercator to display on map
        var location = esri.geometry.geographicToWebMercator(stop.location);

        //Set the best address match as a stop on the route
        if (type === "from") {
          routeParams.stops.features[0] = map.graphics.add(new esri.Graphic(location, fromSymbol, { address:stop.address, score:stop.score }));
        }
        else if (type === "to") {
          routeParams.stops.features[1] = map.graphics.add(new esri.Graphic(location, toSymbol, { address:stop.address, score:stop.score }));
        }

        //If both the "to" and the "from" addresses are set, solve the route
        if (routeParams.stops.features.length === 2) {
          routeTask.solve(routeParams);
        }
      }

      function showRoute(solveResult) {
        directions = solveResult.routeResults[0].directions;
        directionFeatures = directions.features;

        //Add route to the map
        map.graphics.add(new esri.Graphic(directions.mergedGeometry, routeSymbol));

        //Display the total time and distance of the route
        dojo.byId("summary").innerHTML = "<br />   Total distance: " + formatDistance(directions.totalLength, "miles") + "<br />   Total time: " + formatTime(directions.totalTime);

        //List the directions and create hyperlinks for each route segment
        var dirStrings = ["<ol>"];
        dojo.forEach(solveResult.routeResults[0].directions.features, function(feature, i) {
          dirStrings.push("<li onclick='zoomToSegment(" + i + "); return false;' class=\"segment\"><a href=\"#\">" + feature.attributes.text + " (" + formatDistance(feature.attributes.length ,"miles") + ", " + formatTime(feature.attributes.time) + ")</a></li>");
        });
        dirStrings.push("</ol>");
        dojo.byId("directions").innerHTML = dirStrings.join("");

        zoomToFullRoute();
      }

      //Display any errors that were caught when attempting to solve the rotue
      function errorHandler(err) {
        alert("An error occured\n" + err.message + "\n" + err.details.join("\n"));
      }

      //Zoom to the appropriate segment when the user clicks a hyperlink in the directions list
      function zoomToSegment(index) {
        var segment = directionFeatures[index];
        map.setExtent(segment.geometry.getExtent(), true);
        if (! segmentGraphic) {
          segmentGraphic = map.graphics.add(new esri.Graphic(segment.geometry, segmentSymbol));
        }
        else {
          segmentGraphic.setGeometry(segment.geometry);
        }
      }

      function zoomToFullRoute() {
        map.graphics.remove(segmentGraphic);
        segmentGraphic = null;
        map.setExtent(directions.extent, true);
      }

      //Format the time as hours and minutes
      function formatTime(time) {
        var hr = Math.floor(time / 60), //Important to use math.floor with hours
            min = Math.round(time % 60);

        if (hr < 1 && min < 1) {
          return "";
        }
        else if (hr < 1) {
          return min + " minute(s)";
        }

        return hr + " hour(s) " + min + " minute(s)";
      }

      //Round the distance to the nearest hundredth of a unit
      function formatDistance(dist, units) {
        var d = Math.round(dist * 100) / 100;
        if (d === 0) {
          return "";
        }

        return d + " " + units;
      }
    </script>

  </head>
  <body class="claro">

    <input type="text" id="fromTxf" value="380 New York St, Redlands, CA, 92373" size="30" />
    <input type="text" id="toTxf" value="111 W Harbor Dr, San Diego, CA, 92101" size="30" />
    <button onclick="getDirections();">Get Directions</button>
    <br /><br />
    <table>
      <tbody>
        <tr>
          <td>

            <div id="map" style="width:600px; height:400px; border:1px solid #000;"></div>
          </td>
          <td valign="top">
            <div style="width:400px; height:400px; overflow:auto; border:1px solid #000;">
              <div id="summary" onclick="zoomToFullRoute();" class="segment"></div>
              <div id="directions"></div>
            </div>
          </td>
        </tr>

      </tbody>
    </table>
    <ol>
      <li>Enter from/to address (format: &lt;Street, City, State, Zip&gt;).</li>
      <li>Click the 'Get Directions' to get directions.</li>
      <li>Click an item in the directions to zoom to that segment.</li>

    </ol>
  </body>
</html>
0 Kudos