Find a route and directions

Learn how to find a route and directions with the route service.

find a route and directions

Routing is the process of finding the path from an origin to a destination in a street network. You can use the Routing service to find routes, get driving directions, calculate drive times, and solve complicated, multiple vehicle routing problems. To create a route, you typically define a set of stops (origin and one or more destinations) and use the service to find a route with directions. You can also use a number of additional parameters such as barriers and mode of travel to refine the results.

In this tutorial, you define an origin and destination by clicking on the map. These values are used to get a route and directions from the route service. The directions are also displayed on the map.

Prerequisites

The following are required for this tutorial:

  1. An ArcGIS account to access your API keys. If you don't have an account, sign up for free.
  2. Confirm that your system meets the minimum system requirements.
  3. An IDE for Java.

Steps

Open a Java project with Gradle

  1. To start this tutorial, complete the Display a map tutorial or download and unzip the solution into a new folder.

  2. Open the build.gradle file as a project in IntelliJ IDEA.

  3. If you downloaded the solution project, set your API key.

    An API Key enables access to services, web maps, and web scenes hosted in ArcGIS Online.

    1. Go to your developer dashboard to get your API key. For these tutorials, use your default API key. It is scoped to include all of the services demonstrated in the tutorials.

    2. In the IntelliJ IDEA > Project tool window, open src/main/java/com.example.app and click App.

    3. In the start() method, set the API key property on the ArcGISRuntimeEnvironment with your API key.

      App.java
      Change lineChange lineChange lineChange line
      48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 49 50 51 52 53 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54 54
      
      //   Copyright 2020 Esri
      //   Licensed under the Apache License, Version 2.0 (the "License");
      //   you may not use this file except in compliance with the License.
      //   You may obtain a copy of the License at
      //
      //   http://www.apache.org/licenses/LICENSE-2.0
      //
      //   Unless required by applicable law or agreed to in writing, software
      //   distributed under the License is distributed on an "AS IS" BASIS,
      //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      //   See the License for the specific language governing permissions and
      //   limitations under the License.
      
      package com.example.app;
      
      import com.esri.arcgisruntime.ArcGISRuntimeEnvironment;
      import com.esri.arcgisruntime.mapping.ArcGISMap;
      import com.esri.arcgisruntime.mapping.BasemapStyle;
      import com.esri.arcgisruntime.mapping.Viewpoint;
      import com.esri.arcgisruntime.mapping.view.MapView;
      
      import javafx.application.Application;
      import javafx.scene.Scene;
      import javafx.scene.layout.StackPane;
      import javafx.stage.Stage;
      
      public class App extends Application {
      
        private MapView mapView;
      
        public static void main(String[] args) {
          Application.launch(args);
        }
      
        @Override
        public void start(Stage stage) {
      
          // set the title and size of the stage and show it
          stage.setTitle("Display a map tutorial");
          stage.setWidth(800);
          stage.setHeight(700);
          stage.show();
      
          // create a JavaFX scene with a stack pane as the root node, and add it to the scene
          StackPane stackPane = new StackPane();
          Scene scene = new Scene(stackPane);
      
          stage.setScene(scene);
      
          // Note: it is not best practice to store API keys in source code.
          // The API key is referenced here for the convenience of this tutorial.
          String yourApiKey = "YOUR_API_KEY";
          ArcGISRuntimeEnvironment.setApiKey(yourApiKey);
      
          // create a map view to display the map and add it to the stack pane
          mapView = new MapView();
          stackPane.getChildren().add(mapView);
      
          ArcGISMap map = new ArcGISMap(BasemapStyle.ARCGIS_TOPOGRAPHIC);
      
          // set the map on the map view
          mapView.setMap(map);
      
          mapView.setViewpoint(new Viewpoint(34.02700, -118.80543, 144447.638572));
      
        }
      
        /**
         * Stops and releases all resources used in application.
         */
        @Override
        public void stop() {
          if (mapView != null) {
            mapView.dispose();
          }
        }
      
      }
      

Add import statements and variable declarations

Add import statements and variable declarations to reference the packages and classes required for this tutorial.

  1. In the IntelliJ IDEA > Project tool window, open src/main/java/com.example.app and click App.

  2. Add the following imports above the existing imports:

    App.java
    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
    16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48
    
    //   Copyright 2020 Esri
    //   Licensed under the Apache License, Version 2.0 (the "License");
    //   you may not use this file except in compliance with the License.
    //   You may obtain a copy of the License at
    //
    //   http://www.apache.org/licenses/LICENSE-2.0
    //
    //   Unless required by applicable law or agreed to in writing, software
    //   distributed under the License is distributed on an "AS IS" BASIS,
    //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    //   See the License for the specific language governing permissions and
    //   limitations under the License.
    
    package com.example.app;
    
    import com.esri.arcgisruntime.concurrent.ListenableFuture;
    import com.esri.arcgisruntime.geometry.Geometry;
    import com.esri.arcgisruntime.mapping.BasemapStyle;
    import com.esri.arcgisruntime.mapping.Viewpoint;
    import com.esri.arcgisruntime.mapping.view.Graphic;
    import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
    import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
    import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol;
    import com.esri.arcgisruntime.tasks.networkanalysis.Route;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteParameters;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteResult;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteTask;
    import com.esri.arcgisruntime.tasks.networkanalysis.Stop;
    
    import javafx.collections.FXCollections;
    import javafx.collections.ListChangeListener;
    import javafx.collections.ObservableList;
    import javafx.geometry.Point2D;
    import javafx.geometry.Pos;
    import javafx.scene.control.Alert;
    import javafx.scene.control.ListView;
    import javafx.scene.input.MouseButton;
    import java.util.List;
    
    import com.esri.arcgisruntime.ArcGISRuntimeEnvironment;
    import com.esri.arcgisruntime.mapping.ArcGISMap;
    import com.esri.arcgisruntime.mapping.view.MapView;
    
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class App extends Application {
    
      private MapView mapView;
    
      private Graphic routeGraphic;
      private RouteTask routeTask;
      private RouteParameters routeParameters;
      private final ObservableList<Stop> routeStops = FXCollections.observableArrayList();
      private final ListView<String> directionsList = new ListView<>();
    
      public static void main(String[] args) {
        Application.launch(args);
      }
    
      @Override
      public void start(Stage stage) {
    
        // set the title and size of the stage and show it
        stage.setTitle("Find a route and directions tutorial");
        stage.setWidth(800);
        stage.setHeight(700);
        stage.show();
    
        // create a JavaFX scene with a stack pane as the root node
        // and add it to the scene
        StackPane stackPane = new StackPane();
        Scene scene = new Scene(stackPane);
    
        stage.setScene(scene);
    
        // Note: it is not best practice to store API keys in source code.
        // The API key is referenced here for the convenience of this tutorial.
        String yourApiKey = "YOUR_API_KEY";
        ArcGISRuntimeEnvironment.setApiKey(yourApiKey);
    
        // create a MapView to display the map and add it to the stack pane
        mapView = new MapView();
        stackPane.getChildren().add(mapView);
    
        ArcGISMap map = new ArcGISMap(BasemapStyle.ARCGIS_STREETS);
    
        // set the map on the map view
        mapView.setMap(map);
    
        mapView.setViewpoint(new Viewpoint(34.05398, -118.24532, 144447.638572));
    
        directionsList.setMaxSize(400, 250);
        stackPane.getChildren().add(directionsList);
        StackPane.setAlignment(directionsList, Pos.TOP_LEFT);
    
        GraphicsOverlay graphicsOverlay = new GraphicsOverlay();
        mapView.getGraphicsOverlays().add(graphicsOverlay);
    
        routeTask = new RouteTask("https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World");
    
        ListenableFuture<RouteParameters> routeParametersFuture = routeTask.createDefaultParametersAsync();
        routeParametersFuture.addDoneListener(() -> {
          try {
            routeParameters = routeParametersFuture.get();
            routeParameters.setReturnDirections(true);
            directionsList.getItems().add("Click to add two points to the map to find a route.");
    
          } catch (Exception e) {
            Alert alert = new Alert(Alert.AlertType.ERROR, e.toString());
            alert.show();
            e.printStackTrace();
          }
        });
    
        addStopsOnMouseClicked();
    
        routeStops.addListener((ListChangeListener<Stop>) e -> {
          // track the number of stops added to the map, and use it create graphic geometry and symbol text
          int routeStopsSize = routeStops.size();
          // handle user interaction
          if (routeStopsSize == 0) {
            return;
          } else if (routeStopsSize == 1) {
            graphicsOverlay.getGraphics().clear();
            if (!directionsList.getItems().isEmpty())
            directionsList.getItems().clear();
            directionsList.getItems().add("Click to add two points to the map to find a route.");
          }
          // create a blue circle symbol for the stop
          SimpleMarkerSymbol stopMarker = new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, 0xff0000ff, 20);
          // get the stop's geometry
          Geometry routeStopGeometry = routeStops.get(routeStopsSize-1).getGeometry();
    
          graphicsOverlay.getGraphics().add(new Graphic(routeStopGeometry, stopMarker));
    
          if (routeStopsSize == 2) {
            // remove the mouse clicked event if two stops have been added
            mapView.setOnMouseClicked(null);
            routeParameters.setStops(routeStops);
    
            // get the route and display it
            ListenableFuture<RouteResult> routeResultFuture = routeTask.solveRouteAsync(routeParameters);
            routeResultFuture.addDoneListener(() -> {
              try {
                RouteResult result = routeResultFuture.get();
                List<Route> routes = result.getRoutes();
    
                if (!routes.isEmpty()) {
                  Route route = routes.get(0);
                  Geometry shape = route.getRouteGeometry();
                  routeGraphic = new Graphic(shape, new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, 0xff0000ff, 2));
                  graphicsOverlay.getGraphics().add(routeGraphic);
    
                  // get the direction text for each maneuver and display it as a list in the UI
                  route.getDirectionManeuvers().forEach(step -> directionsList.getItems().add(step.getDirectionText()));
                  // reset stops and re-enable mapview interactions once the route task has completed
                  routeStops.clear();
                  addStopsOnMouseClicked();
    
                }
    
              } catch (Exception ex) {
                ex.printStackTrace();
              }
            });
    
          }
    
        });
    
      }
    
      private void addStopsOnMouseClicked() {
        mapView.setOnMouseClicked(event -> {
          if (event.isStillSincePress() && event.getButton() == MouseButton.PRIMARY) {
            Point2D mapPoint = new Point2D(event.getX(), event.getY());
            routeStops.add(new Stop(mapView.screenToLocation(mapPoint)));
          }
        });
      }
    
      /**
       * Stops and releases all resources used in application.
       */
      @Override
      public void stop() {
        if (mapView != null) {
          mapView.dispose();
        }
      }
    
    }
    
  3. Within the App class, add the following member variables to easily reference them from other parts of the application:

    Member variables ensure that objects are not deallocated while asynchronous methods are executing. If an object is deallocated while one of its asynchronous methods is executing, the completion callback closure will never be called.

    App.java
    Add line.Add line.Add line.Add line.Add line.
    51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 52 53 54 55 56 57 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 57 56 55 54 52 50 48 46 44 42 40 38 36 34 32 30 28 26 24 22 20 18 16 15 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 13 12 11 10 9 8 7 6 5 5 5 5 5 5 5 5 5 5 5 5
    
    //   Copyright 2020 Esri
    //   Licensed under the Apache License, Version 2.0 (the "License");
    //   you may not use this file except in compliance with the License.
    //   You may obtain a copy of the License at
    //
    //   http://www.apache.org/licenses/LICENSE-2.0
    //
    //   Unless required by applicable law or agreed to in writing, software
    //   distributed under the License is distributed on an "AS IS" BASIS,
    //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    //   See the License for the specific language governing permissions and
    //   limitations under the License.
    
    package com.example.app;
    
    import com.esri.arcgisruntime.concurrent.ListenableFuture;
    import com.esri.arcgisruntime.geometry.Geometry;
    import com.esri.arcgisruntime.mapping.BasemapStyle;
    import com.esri.arcgisruntime.mapping.Viewpoint;
    import com.esri.arcgisruntime.mapping.view.Graphic;
    import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
    import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
    import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol;
    import com.esri.arcgisruntime.tasks.networkanalysis.Route;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteParameters;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteResult;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteTask;
    import com.esri.arcgisruntime.tasks.networkanalysis.Stop;
    
    import javafx.collections.FXCollections;
    import javafx.collections.ListChangeListener;
    import javafx.collections.ObservableList;
    import javafx.geometry.Point2D;
    import javafx.geometry.Pos;
    import javafx.scene.control.Alert;
    import javafx.scene.control.ListView;
    import javafx.scene.input.MouseButton;
    import java.util.List;
    
    import com.esri.arcgisruntime.ArcGISRuntimeEnvironment;
    import com.esri.arcgisruntime.mapping.ArcGISMap;
    import com.esri.arcgisruntime.mapping.view.MapView;
    
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class App extends Application {
    
      private MapView mapView;
    
      private Graphic routeGraphic;
      private RouteTask routeTask;
      private RouteParameters routeParameters;
      private final ObservableList<Stop> routeStops = FXCollections.observableArrayList();
      private final ListView<String> directionsList = new ListView<>();
    
      public static void main(String[] args) {
        Application.launch(args);
      }
    
      @Override
      public void start(Stage stage) {
    
        // set the title and size of the stage and show it
        stage.setTitle("Find a route and directions tutorial");
        stage.setWidth(800);
        stage.setHeight(700);
        stage.show();
    
        // create a JavaFX scene with a stack pane as the root node
        // and add it to the scene
        StackPane stackPane = new StackPane();
        Scene scene = new Scene(stackPane);
    
        stage.setScene(scene);
    
        // Note: it is not best practice to store API keys in source code.
        // The API key is referenced here for the convenience of this tutorial.
        String yourApiKey = "YOUR_API_KEY";
        ArcGISRuntimeEnvironment.setApiKey(yourApiKey);
    
        // create a MapView to display the map and add it to the stack pane
        mapView = new MapView();
        stackPane.getChildren().add(mapView);
    
        ArcGISMap map = new ArcGISMap(BasemapStyle.ARCGIS_STREETS);
    
        // set the map on the map view
        mapView.setMap(map);
    
        mapView.setViewpoint(new Viewpoint(34.05398, -118.24532, 144447.638572));
    
        directionsList.setMaxSize(400, 250);
        stackPane.getChildren().add(directionsList);
        StackPane.setAlignment(directionsList, Pos.TOP_LEFT);
    
        GraphicsOverlay graphicsOverlay = new GraphicsOverlay();
        mapView.getGraphicsOverlays().add(graphicsOverlay);
    
        routeTask = new RouteTask("https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World");
    
        ListenableFuture<RouteParameters> routeParametersFuture = routeTask.createDefaultParametersAsync();
        routeParametersFuture.addDoneListener(() -> {
          try {
            routeParameters = routeParametersFuture.get();
            routeParameters.setReturnDirections(true);
            directionsList.getItems().add("Click to add two points to the map to find a route.");
    
          } catch (Exception e) {
            Alert alert = new Alert(Alert.AlertType.ERROR, e.toString());
            alert.show();
            e.printStackTrace();
          }
        });
    
        addStopsOnMouseClicked();
    
        routeStops.addListener((ListChangeListener<Stop>) e -> {
          // track the number of stops added to the map, and use it create graphic geometry and symbol text
          int routeStopsSize = routeStops.size();
          // handle user interaction
          if (routeStopsSize == 0) {
            return;
          } else if (routeStopsSize == 1) {
            graphicsOverlay.getGraphics().clear();
            if (!directionsList.getItems().isEmpty())
            directionsList.getItems().clear();
            directionsList.getItems().add("Click to add two points to the map to find a route.");
          }
          // create a blue circle symbol for the stop
          SimpleMarkerSymbol stopMarker = new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, 0xff0000ff, 20);
          // get the stop's geometry
          Geometry routeStopGeometry = routeStops.get(routeStopsSize-1).getGeometry();
    
          graphicsOverlay.getGraphics().add(new Graphic(routeStopGeometry, stopMarker));
    
          if (routeStopsSize == 2) {
            // remove the mouse clicked event if two stops have been added
            mapView.setOnMouseClicked(null);
            routeParameters.setStops(routeStops);
    
            // get the route and display it
            ListenableFuture<RouteResult> routeResultFuture = routeTask.solveRouteAsync(routeParameters);
            routeResultFuture.addDoneListener(() -> {
              try {
                RouteResult result = routeResultFuture.get();
                List<Route> routes = result.getRoutes();
    
                if (!routes.isEmpty()) {
                  Route route = routes.get(0);
                  Geometry shape = route.getRouteGeometry();
                  routeGraphic = new Graphic(shape, new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, 0xff0000ff, 2));
                  graphicsOverlay.getGraphics().add(routeGraphic);
    
                  // get the direction text for each maneuver and display it as a list in the UI
                  route.getDirectionManeuvers().forEach(step -> directionsList.getItems().add(step.getDirectionText()));
                  // reset stops and re-enable mapview interactions once the route task has completed
                  routeStops.clear();
                  addStopsOnMouseClicked();
    
                }
    
              } catch (Exception ex) {
                ex.printStackTrace();
              }
            });
    
          }
    
        });
    
      }
    
      private void addStopsOnMouseClicked() {
        mapView.setOnMouseClicked(event -> {
          if (event.isStillSincePress() && event.getButton() == MouseButton.PRIMARY) {
            Point2D mapPoint = new Point2D(event.getX(), event.getY());
            routeStops.add(new Stop(mapView.screenToLocation(mapPoint)));
          }
        });
      }
    
      /**
       * Stops and releases all resources used in application.
       */
      @Override
      public void stop() {
        if (mapView != null) {
          mapView.dispose();
        }
      }
    
    }
    

Update the map

A streets basemap layer is typically used in routing applications. Update the basemap to use the ARCGIS_STREETS basemap style, and change the position of the map to center on Los Angeles.

  1. Update the Basemap style property from ARCGIS_TOPOGRAPHIC to ARCGIS_STREETS.

  2. Update the latitude and longitude coordinates to center on Los Angeles.

    App.java
    Change lineChange line
    84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 85 86 87 88 89 90 91 92 93 94 94 93 92 91 90 88 86 84 82 80 78 76 74 72 70 68 66 64 62 60 58 56 54 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 -1 -2 -3 -4 -4 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -13 -13 -13 -13 -13 -13 -13 -13 -13 -13 -13
    
    //   Copyright 2020 Esri
    //   Licensed under the Apache License, Version 2.0 (the "License");
    //   you may not use this file except in compliance with the License.
    //   You may obtain a copy of the License at
    //
    //   http://www.apache.org/licenses/LICENSE-2.0
    //
    //   Unless required by applicable law or agreed to in writing, software
    //   distributed under the License is distributed on an "AS IS" BASIS,
    //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    //   See the License for the specific language governing permissions and
    //   limitations under the License.
    
    package com.example.app;
    
    import com.esri.arcgisruntime.concurrent.ListenableFuture;
    import com.esri.arcgisruntime.geometry.Geometry;
    import com.esri.arcgisruntime.mapping.BasemapStyle;
    import com.esri.arcgisruntime.mapping.Viewpoint;
    import com.esri.arcgisruntime.mapping.view.Graphic;
    import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
    import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
    import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol;
    import com.esri.arcgisruntime.tasks.networkanalysis.Route;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteParameters;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteResult;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteTask;
    import com.esri.arcgisruntime.tasks.networkanalysis.Stop;
    
    import javafx.collections.FXCollections;
    import javafx.collections.ListChangeListener;
    import javafx.collections.ObservableList;
    import javafx.geometry.Point2D;
    import javafx.geometry.Pos;
    import javafx.scene.control.Alert;
    import javafx.scene.control.ListView;
    import javafx.scene.input.MouseButton;
    import java.util.List;
    
    import com.esri.arcgisruntime.ArcGISRuntimeEnvironment;
    import com.esri.arcgisruntime.mapping.ArcGISMap;
    import com.esri.arcgisruntime.mapping.view.MapView;
    
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class App extends Application {
    
      private MapView mapView;
    
      private Graphic routeGraphic;
      private RouteTask routeTask;
      private RouteParameters routeParameters;
      private final ObservableList<Stop> routeStops = FXCollections.observableArrayList();
      private final ListView<String> directionsList = new ListView<>();
    
      public static void main(String[] args) {
        Application.launch(args);
      }
    
      @Override
      public void start(Stage stage) {
    
        // set the title and size of the stage and show it
        stage.setTitle("Find a route and directions tutorial");
        stage.setWidth(800);
        stage.setHeight(700);
        stage.show();
    
        // create a JavaFX scene with a stack pane as the root node
        // and add it to the scene
        StackPane stackPane = new StackPane();
        Scene scene = new Scene(stackPane);
    
        stage.setScene(scene);
    
        // Note: it is not best practice to store API keys in source code.
        // The API key is referenced here for the convenience of this tutorial.
        String yourApiKey = "YOUR_API_KEY";
        ArcGISRuntimeEnvironment.setApiKey(yourApiKey);
    
        // create a MapView to display the map and add it to the stack pane
        mapView = new MapView();
        stackPane.getChildren().add(mapView);
    
        ArcGISMap map = new ArcGISMap(BasemapStyle.ARCGIS_STREETS);
    
        // set the map on the map view
        mapView.setMap(map);
    
        mapView.setViewpoint(new Viewpoint(34.05398, -118.24532, 144447.638572));
    
        directionsList.setMaxSize(400, 250);
        stackPane.getChildren().add(directionsList);
        StackPane.setAlignment(directionsList, Pos.TOP_LEFT);
    
        GraphicsOverlay graphicsOverlay = new GraphicsOverlay();
        mapView.getGraphicsOverlays().add(graphicsOverlay);
    
        routeTask = new RouteTask("https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World");
    
        ListenableFuture<RouteParameters> routeParametersFuture = routeTask.createDefaultParametersAsync();
        routeParametersFuture.addDoneListener(() -> {
          try {
            routeParameters = routeParametersFuture.get();
            routeParameters.setReturnDirections(true);
            directionsList.getItems().add("Click to add two points to the map to find a route.");
    
          } catch (Exception e) {
            Alert alert = new Alert(Alert.AlertType.ERROR, e.toString());
            alert.show();
            e.printStackTrace();
          }
        });
    
        addStopsOnMouseClicked();
    
        routeStops.addListener((ListChangeListener<Stop>) e -> {
          // track the number of stops added to the map, and use it create graphic geometry and symbol text
          int routeStopsSize = routeStops.size();
          // handle user interaction
          if (routeStopsSize == 0) {
            return;
          } else if (routeStopsSize == 1) {
            graphicsOverlay.getGraphics().clear();
            if (!directionsList.getItems().isEmpty())
            directionsList.getItems().clear();
            directionsList.getItems().add("Click to add two points to the map to find a route.");
          }
          // create a blue circle symbol for the stop
          SimpleMarkerSymbol stopMarker = new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, 0xff0000ff, 20);
          // get the stop's geometry
          Geometry routeStopGeometry = routeStops.get(routeStopsSize-1).getGeometry();
    
          graphicsOverlay.getGraphics().add(new Graphic(routeStopGeometry, stopMarker));
    
          if (routeStopsSize == 2) {
            // remove the mouse clicked event if two stops have been added
            mapView.setOnMouseClicked(null);
            routeParameters.setStops(routeStops);
    
            // get the route and display it
            ListenableFuture<RouteResult> routeResultFuture = routeTask.solveRouteAsync(routeParameters);
            routeResultFuture.addDoneListener(() -> {
              try {
                RouteResult result = routeResultFuture.get();
                List<Route> routes = result.getRoutes();
    
                if (!routes.isEmpty()) {
                  Route route = routes.get(0);
                  Geometry shape = route.getRouteGeometry();
                  routeGraphic = new Graphic(shape, new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, 0xff0000ff, 2));
                  graphicsOverlay.getGraphics().add(routeGraphic);
    
                  // get the direction text for each maneuver and display it as a list in the UI
                  route.getDirectionManeuvers().forEach(step -> directionsList.getItems().add(step.getDirectionText()));
                  // reset stops and re-enable mapview interactions once the route task has completed
                  routeStops.clear();
                  addStopsOnMouseClicked();
    
                }
    
              } catch (Exception ex) {
                ex.printStackTrace();
              }
            });
    
          }
    
        });
    
      }
    
      private void addStopsOnMouseClicked() {
        mapView.setOnMouseClicked(event -> {
          if (event.isStillSincePress() && event.getButton() == MouseButton.PRIMARY) {
            Point2D mapPoint = new Point2D(event.getX(), event.getY());
            routeStops.add(new Stop(mapView.screenToLocation(mapPoint)));
          }
        });
      }
    
      /**
       * Stops and releases all resources used in application.
       */
      @Override
      public void stop() {
        if (mapView != null) {
          mapView.dispose();
        }
      }
    
    }
    

Add a UI to display driving directions

To display the turn-by-turn directions from the route, a UI element is required.

  1. In the start() method, set the maximum size of the directionsList (a JavaFX ListView which will display a vertical list of directions), and then add it to the stackPane.

    App.java
    Add line.Add line.Add line.
    88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 88 89 90 91 92 93 94 95 96 97 98 98 96 94 92 90 88 86 84 82 80 78 76 74 72 70 68 66 64 62 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 4 4 3 2 1 0 -1 -2 -3 -4 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5 -5
    
    //   Copyright 2020 Esri
    //   Licensed under the Apache License, Version 2.0 (the "License");
    //   you may not use this file except in compliance with the License.
    //   You may obtain a copy of the License at
    //
    //   http://www.apache.org/licenses/LICENSE-2.0
    //
    //   Unless required by applicable law or agreed to in writing, software
    //   distributed under the License is distributed on an "AS IS" BASIS,
    //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    //   See the License for the specific language governing permissions and
    //   limitations under the License.
    
    package com.example.app;
    
    import com.esri.arcgisruntime.concurrent.ListenableFuture;
    import com.esri.arcgisruntime.geometry.Geometry;
    import com.esri.arcgisruntime.mapping.BasemapStyle;
    import com.esri.arcgisruntime.mapping.Viewpoint;
    import com.esri.arcgisruntime.mapping.view.Graphic;
    import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
    import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
    import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol;
    import com.esri.arcgisruntime.tasks.networkanalysis.Route;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteParameters;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteResult;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteTask;
    import com.esri.arcgisruntime.tasks.networkanalysis.Stop;
    
    import javafx.collections.FXCollections;
    import javafx.collections.ListChangeListener;
    import javafx.collections.ObservableList;
    import javafx.geometry.Point2D;
    import javafx.geometry.Pos;
    import javafx.scene.control.Alert;
    import javafx.scene.control.ListView;
    import javafx.scene.input.MouseButton;
    import java.util.List;
    
    import com.esri.arcgisruntime.ArcGISRuntimeEnvironment;
    import com.esri.arcgisruntime.mapping.ArcGISMap;
    import com.esri.arcgisruntime.mapping.view.MapView;
    
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class App extends Application {
    
      private MapView mapView;
    
      private Graphic routeGraphic;
      private RouteTask routeTask;
      private RouteParameters routeParameters;
      private final ObservableList<Stop> routeStops = FXCollections.observableArrayList();
      private final ListView<String> directionsList = new ListView<>();
    
      public static void main(String[] args) {
        Application.launch(args);
      }
    
      @Override
      public void start(Stage stage) {
    
        // set the title and size of the stage and show it
        stage.setTitle("Find a route and directions tutorial");
        stage.setWidth(800);
        stage.setHeight(700);
        stage.show();
    
        // create a JavaFX scene with a stack pane as the root node
        // and add it to the scene
        StackPane stackPane = new StackPane();
        Scene scene = new Scene(stackPane);
    
        stage.setScene(scene);
    
        // Note: it is not best practice to store API keys in source code.
        // The API key is referenced here for the convenience of this tutorial.
        String yourApiKey = "YOUR_API_KEY";
        ArcGISRuntimeEnvironment.setApiKey(yourApiKey);
    
        // create a MapView to display the map and add it to the stack pane
        mapView = new MapView();
        stackPane.getChildren().add(mapView);
    
        ArcGISMap map = new ArcGISMap(BasemapStyle.ARCGIS_STREETS);
    
        // set the map on the map view
        mapView.setMap(map);
    
        mapView.setViewpoint(new Viewpoint(34.05398, -118.24532, 144447.638572));
    
        directionsList.setMaxSize(400, 250);
        stackPane.getChildren().add(directionsList);
        StackPane.setAlignment(directionsList, Pos.TOP_LEFT);
    
        GraphicsOverlay graphicsOverlay = new GraphicsOverlay();
        mapView.getGraphicsOverlays().add(graphicsOverlay);
    
        routeTask = new RouteTask("https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World");
    
        ListenableFuture<RouteParameters> routeParametersFuture = routeTask.createDefaultParametersAsync();
        routeParametersFuture.addDoneListener(() -> {
          try {
            routeParameters = routeParametersFuture.get();
            routeParameters.setReturnDirections(true);
            directionsList.getItems().add("Click to add two points to the map to find a route.");
    
          } catch (Exception e) {
            Alert alert = new Alert(Alert.AlertType.ERROR, e.toString());
            alert.show();
            e.printStackTrace();
          }
        });
    
        addStopsOnMouseClicked();
    
        routeStops.addListener((ListChangeListener<Stop>) e -> {
          // track the number of stops added to the map, and use it create graphic geometry and symbol text
          int routeStopsSize = routeStops.size();
          // handle user interaction
          if (routeStopsSize == 0) {
            return;
          } else if (routeStopsSize == 1) {
            graphicsOverlay.getGraphics().clear();
            if (!directionsList.getItems().isEmpty())
            directionsList.getItems().clear();
            directionsList.getItems().add("Click to add two points to the map to find a route.");
          }
          // create a blue circle symbol for the stop
          SimpleMarkerSymbol stopMarker = new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, 0xff0000ff, 20);
          // get the stop's geometry
          Geometry routeStopGeometry = routeStops.get(routeStopsSize-1).getGeometry();
    
          graphicsOverlay.getGraphics().add(new Graphic(routeStopGeometry, stopMarker));
    
          if (routeStopsSize == 2) {
            // remove the mouse clicked event if two stops have been added
            mapView.setOnMouseClicked(null);
            routeParameters.setStops(routeStops);
    
            // get the route and display it
            ListenableFuture<RouteResult> routeResultFuture = routeTask.solveRouteAsync(routeParameters);
            routeResultFuture.addDoneListener(() -> {
              try {
                RouteResult result = routeResultFuture.get();
                List<Route> routes = result.getRoutes();
    
                if (!routes.isEmpty()) {
                  Route route = routes.get(0);
                  Geometry shape = route.getRouteGeometry();
                  routeGraphic = new Graphic(shape, new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, 0xff0000ff, 2));
                  graphicsOverlay.getGraphics().add(routeGraphic);
    
                  // get the direction text for each maneuver and display it as a list in the UI
                  route.getDirectionManeuvers().forEach(step -> directionsList.getItems().add(step.getDirectionText()));
                  // reset stops and re-enable mapview interactions once the route task has completed
                  routeStops.clear();
                  addStopsOnMouseClicked();
    
                }
    
              } catch (Exception ex) {
                ex.printStackTrace();
              }
            });
    
          }
    
        });
    
      }
    
      private void addStopsOnMouseClicked() {
        mapView.setOnMouseClicked(event -> {
          if (event.isStillSincePress() && event.getButton() == MouseButton.PRIMARY) {
            Point2D mapPoint = new Point2D(event.getX(), event.getY());
            routeStops.add(new Stop(mapView.screenToLocation(mapPoint)));
          }
        });
      }
    
      /**
       * Stops and releases all resources used in application.
       */
      @Override
      public void stop() {
        if (mapView != null) {
          mapView.dispose();
        }
      }
    
    }
    

Add a graphics overlay

A graphics overlay is a container for graphics. Graphics will be added later in this tutorial as a visual means to display the route stops and route result on the map.

  1. Create a new GraphicsOverlay and add it to the mapView.

    App.java
    Add line.Add line.
    95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 95 96 97 98 99 100 101 101 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 29 29 28 27 26 25 24 23 22 21 20 20 20 20 20 20 20 20 20 20 20 20
    
    //   Copyright 2020 Esri
    //   Licensed under the Apache License, Version 2.0 (the "License");
    //   you may not use this file except in compliance with the License.
    //   You may obtain a copy of the License at
    //
    //   http://www.apache.org/licenses/LICENSE-2.0
    //
    //   Unless required by applicable law or agreed to in writing, software
    //   distributed under the License is distributed on an "AS IS" BASIS,
    //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    //   See the License for the specific language governing permissions and
    //   limitations under the License.
    
    package com.example.app;
    
    import com.esri.arcgisruntime.concurrent.ListenableFuture;
    import com.esri.arcgisruntime.geometry.Geometry;
    import com.esri.arcgisruntime.mapping.BasemapStyle;
    import com.esri.arcgisruntime.mapping.Viewpoint;
    import com.esri.arcgisruntime.mapping.view.Graphic;
    import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
    import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
    import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol;
    import com.esri.arcgisruntime.tasks.networkanalysis.Route;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteParameters;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteResult;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteTask;
    import com.esri.arcgisruntime.tasks.networkanalysis.Stop;
    
    import javafx.collections.FXCollections;
    import javafx.collections.ListChangeListener;
    import javafx.collections.ObservableList;
    import javafx.geometry.Point2D;
    import javafx.geometry.Pos;
    import javafx.scene.control.Alert;
    import javafx.scene.control.ListView;
    import javafx.scene.input.MouseButton;
    import java.util.List;
    
    import com.esri.arcgisruntime.ArcGISRuntimeEnvironment;
    import com.esri.arcgisruntime.mapping.ArcGISMap;
    import com.esri.arcgisruntime.mapping.view.MapView;
    
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class App extends Application {
    
      private MapView mapView;
    
      private Graphic routeGraphic;
      private RouteTask routeTask;
      private RouteParameters routeParameters;
      private final ObservableList<Stop> routeStops = FXCollections.observableArrayList();
      private final ListView<String> directionsList = new ListView<>();
    
      public static void main(String[] args) {
        Application.launch(args);
      }
    
      @Override
      public void start(Stage stage) {
    
        // set the title and size of the stage and show it
        stage.setTitle("Find a route and directions tutorial");
        stage.setWidth(800);
        stage.setHeight(700);
        stage.show();
    
        // create a JavaFX scene with a stack pane as the root node
        // and add it to the scene
        StackPane stackPane = new StackPane();
        Scene scene = new Scene(stackPane);
    
        stage.setScene(scene);
    
        // Note: it is not best practice to store API keys in source code.
        // The API key is referenced here for the convenience of this tutorial.
        String yourApiKey = "YOUR_API_KEY";
        ArcGISRuntimeEnvironment.setApiKey(yourApiKey);
    
        // create a MapView to display the map and add it to the stack pane
        mapView = new MapView();
        stackPane.getChildren().add(mapView);
    
        ArcGISMap map = new ArcGISMap(BasemapStyle.ARCGIS_STREETS);
    
        // set the map on the map view
        mapView.setMap(map);
    
        mapView.setViewpoint(new Viewpoint(34.05398, -118.24532, 144447.638572));
    
        directionsList.setMaxSize(400, 250);
        stackPane.getChildren().add(directionsList);
        StackPane.setAlignment(directionsList, Pos.TOP_LEFT);
    
        GraphicsOverlay graphicsOverlay = new GraphicsOverlay();
        mapView.getGraphicsOverlays().add(graphicsOverlay);
    
        routeTask = new RouteTask("https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World");
    
        ListenableFuture<RouteParameters> routeParametersFuture = routeTask.createDefaultParametersAsync();
        routeParametersFuture.addDoneListener(() -> {
          try {
            routeParameters = routeParametersFuture.get();
            routeParameters.setReturnDirections(true);
            directionsList.getItems().add("Click to add two points to the map to find a route.");
    
          } catch (Exception e) {
            Alert alert = new Alert(Alert.AlertType.ERROR, e.toString());
            alert.show();
            e.printStackTrace();
          }
        });
    
        addStopsOnMouseClicked();
    
        routeStops.addListener((ListChangeListener<Stop>) e -> {
          // track the number of stops added to the map, and use it create graphic geometry and symbol text
          int routeStopsSize = routeStops.size();
          // handle user interaction
          if (routeStopsSize == 0) {
            return;
          } else if (routeStopsSize == 1) {
            graphicsOverlay.getGraphics().clear();
            if (!directionsList.getItems().isEmpty())
            directionsList.getItems().clear();
            directionsList.getItems().add("Click to add two points to the map to find a route.");
          }
          // create a blue circle symbol for the stop
          SimpleMarkerSymbol stopMarker = new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, 0xff0000ff, 20);
          // get the stop's geometry
          Geometry routeStopGeometry = routeStops.get(routeStopsSize-1).getGeometry();
    
          graphicsOverlay.getGraphics().add(new Graphic(routeStopGeometry, stopMarker));
    
          if (routeStopsSize == 2) {
            // remove the mouse clicked event if two stops have been added
            mapView.setOnMouseClicked(null);
            routeParameters.setStops(routeStops);
    
            // get the route and display it
            ListenableFuture<RouteResult> routeResultFuture = routeTask.solveRouteAsync(routeParameters);
            routeResultFuture.addDoneListener(() -> {
              try {
                RouteResult result = routeResultFuture.get();
                List<Route> routes = result.getRoutes();
    
                if (!routes.isEmpty()) {
                  Route route = routes.get(0);
                  Geometry shape = route.getRouteGeometry();
                  routeGraphic = new Graphic(shape, new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, 0xff0000ff, 2));
                  graphicsOverlay.getGraphics().add(routeGraphic);
    
                  // get the direction text for each maneuver and display it as a list in the UI
                  route.getDirectionManeuvers().forEach(step -> directionsList.getItems().add(step.getDirectionText()));
                  // reset stops and re-enable mapview interactions once the route task has completed
                  routeStops.clear();
                  addStopsOnMouseClicked();
    
                }
    
              } catch (Exception ex) {
                ex.printStackTrace();
              }
            });
    
          }
    
        });
    
      }
    
      private void addStopsOnMouseClicked() {
        mapView.setOnMouseClicked(event -> {
          if (event.isStillSincePress() && event.getButton() == MouseButton.PRIMARY) {
            Point2D mapPoint = new Point2D(event.getX(), event.getY());
            routeStops.add(new Stop(mapView.screenToLocation(mapPoint)));
          }
        });
      }
    
      /**
       * Stops and releases all resources used in application.
       */
      @Override
      public void stop() {
        if (mapView != null) {
          mapView.dispose();
        }
      }
    
    }
    

Create a route task and route parameters

A task makes a request to a service and returns the results. Use the RouteTask class to access a routing service.A routing service with global coverage is provided by the ArcGIS Platform. You can also publish custom routing services using ArcGIS Enterprise.

  1. Create a RouteTask with a string URL to reference the ArcGIS Platform's routing service.

    App.java
    Add line.
    99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 100 101 102 103 104 104 104 104 104 104 104 104 104 104 104 104 104 104 103 102 101 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 47 47 46 45 44 43 42 41 40 39 38 38 38 38 38 38 38 38 38 38 38 38
    
    //   Copyright 2020 Esri
    //   Licensed under the Apache License, Version 2.0 (the "License");
    //   you may not use this file except in compliance with the License.
    //   You may obtain a copy of the License at
    //
    //   http://www.apache.org/licenses/LICENSE-2.0
    //
    //   Unless required by applicable law or agreed to in writing, software
    //   distributed under the License is distributed on an "AS IS" BASIS,
    //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    //   See the License for the specific language governing permissions and
    //   limitations under the License.
    
    package com.example.app;
    
    import com.esri.arcgisruntime.concurrent.ListenableFuture;
    import com.esri.arcgisruntime.geometry.Geometry;
    import com.esri.arcgisruntime.mapping.BasemapStyle;
    import com.esri.arcgisruntime.mapping.Viewpoint;
    import com.esri.arcgisruntime.mapping.view.Graphic;
    import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
    import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
    import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol;
    import com.esri.arcgisruntime.tasks.networkanalysis.Route;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteParameters;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteResult;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteTask;
    import com.esri.arcgisruntime.tasks.networkanalysis.Stop;
    
    import javafx.collections.FXCollections;
    import javafx.collections.ListChangeListener;
    import javafx.collections.ObservableList;
    import javafx.geometry.Point2D;
    import javafx.geometry.Pos;
    import javafx.scene.control.Alert;
    import javafx.scene.control.ListView;
    import javafx.scene.input.MouseButton;
    import java.util.List;
    
    import com.esri.arcgisruntime.ArcGISRuntimeEnvironment;
    import com.esri.arcgisruntime.mapping.ArcGISMap;
    import com.esri.arcgisruntime.mapping.view.MapView;
    
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class App extends Application {
    
      private MapView mapView;
    
      private Graphic routeGraphic;
      private RouteTask routeTask;
      private RouteParameters routeParameters;
      private final ObservableList<Stop> routeStops = FXCollections.observableArrayList();
      private final ListView<String> directionsList = new ListView<>();
    
      public static void main(String[] args) {
        Application.launch(args);
      }
    
      @Override
      public void start(Stage stage) {
    
        // set the title and size of the stage and show it
        stage.setTitle("Find a route and directions tutorial");
        stage.setWidth(800);
        stage.setHeight(700);
        stage.show();
    
        // create a JavaFX scene with a stack pane as the root node
        // and add it to the scene
        StackPane stackPane = new StackPane();
        Scene scene = new Scene(stackPane);
    
        stage.setScene(scene);
    
        // Note: it is not best practice to store API keys in source code.
        // The API key is referenced here for the convenience of this tutorial.
        String yourApiKey = "YOUR_API_KEY";
        ArcGISRuntimeEnvironment.setApiKey(yourApiKey);
    
        // create a MapView to display the map and add it to the stack pane
        mapView = new MapView();
        stackPane.getChildren().add(mapView);
    
        ArcGISMap map = new ArcGISMap(BasemapStyle.ARCGIS_STREETS);
    
        // set the map on the map view
        mapView.setMap(map);
    
        mapView.setViewpoint(new Viewpoint(34.05398, -118.24532, 144447.638572));
    
        directionsList.setMaxSize(400, 250);
        stackPane.getChildren().add(directionsList);
        StackPane.setAlignment(directionsList, Pos.TOP_LEFT);
    
        GraphicsOverlay graphicsOverlay = new GraphicsOverlay();
        mapView.getGraphicsOverlays().add(graphicsOverlay);
    
        routeTask = new RouteTask("https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World");
    
        ListenableFuture<RouteParameters> routeParametersFuture = routeTask.createDefaultParametersAsync();
        routeParametersFuture.addDoneListener(() -> {
          try {
            routeParameters = routeParametersFuture.get();
            routeParameters.setReturnDirections(true);
            directionsList.getItems().add("Click to add two points to the map to find a route.");
    
          } catch (Exception e) {
            Alert alert = new Alert(Alert.AlertType.ERROR, e.toString());
            alert.show();
            e.printStackTrace();
          }
        });
    
        addStopsOnMouseClicked();
    
        routeStops.addListener((ListChangeListener<Stop>) e -> {
          // track the number of stops added to the map, and use it create graphic geometry and symbol text
          int routeStopsSize = routeStops.size();
          // handle user interaction
          if (routeStopsSize == 0) {
            return;
          } else if (routeStopsSize == 1) {
            graphicsOverlay.getGraphics().clear();
            if (!directionsList.getItems().isEmpty())
            directionsList.getItems().clear();
            directionsList.getItems().add("Click to add two points to the map to find a route.");
          }
          // create a blue circle symbol for the stop
          SimpleMarkerSymbol stopMarker = new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, 0xff0000ff, 20);
          // get the stop's geometry
          Geometry routeStopGeometry = routeStops.get(routeStopsSize-1).getGeometry();
    
          graphicsOverlay.getGraphics().add(new Graphic(routeStopGeometry, stopMarker));
    
          if (routeStopsSize == 2) {
            // remove the mouse clicked event if two stops have been added
            mapView.setOnMouseClicked(null);
            routeParameters.setStops(routeStops);
    
            // get the route and display it
            ListenableFuture<RouteResult> routeResultFuture = routeTask.solveRouteAsync(routeParameters);
            routeResultFuture.addDoneListener(() -> {
              try {
                RouteResult result = routeResultFuture.get();
                List<Route> routes = result.getRoutes();
    
                if (!routes.isEmpty()) {
                  Route route = routes.get(0);
                  Geometry shape = route.getRouteGeometry();
                  routeGraphic = new Graphic(shape, new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, 0xff0000ff, 2));
                  graphicsOverlay.getGraphics().add(routeGraphic);
    
                  // get the direction text for each maneuver and display it as a list in the UI
                  route.getDirectionManeuvers().forEach(step -> directionsList.getItems().add(step.getDirectionText()));
                  // reset stops and re-enable mapview interactions once the route task has completed
                  routeStops.clear();
                  addStopsOnMouseClicked();
    
                }
    
              } catch (Exception ex) {
                ex.printStackTrace();
              }
            });
    
          }
    
        });
    
      }
    
      private void addStopsOnMouseClicked() {
        mapView.setOnMouseClicked(event -> {
          if (event.isStillSincePress() && event.getButton() == MouseButton.PRIMARY) {
            Point2D mapPoint = new Point2D(event.getX(), event.getY());
            routeStops.add(new Stop(mapView.screenToLocation(mapPoint)));
          }
        });
      }
    
      /**
       * Stops and releases all resources used in application.
       */
      @Override
      public void stop() {
        if (mapView != null) {
          mapView.dispose();
        }
      }
    
    }
    
  2. Get default RouteParameterss from the routeTask and set the return directions property to true. This specifies that the route results should include turn-by-turn directions. Add a UI text prompt.

    The createDefaultParametersAsync() method is asynchronous and you must handle its completion and check for errors.

    App.java
    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
    102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 61 61 60 59 58 57 56 55 54 53 52 52 52 52 52 52 52 52 52 52 52 52
    
    //   Copyright 2020 Esri
    //   Licensed under the Apache License, Version 2.0 (the "License");
    //   you may not use this file except in compliance with the License.
    //   You may obtain a copy of the License at
    //
    //   http://www.apache.org/licenses/LICENSE-2.0
    //
    //   Unless required by applicable law or agreed to in writing, software
    //   distributed under the License is distributed on an "AS IS" BASIS,
    //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    //   See the License for the specific language governing permissions and
    //   limitations under the License.
    
    package com.example.app;
    
    import com.esri.arcgisruntime.concurrent.ListenableFuture;
    import com.esri.arcgisruntime.geometry.Geometry;
    import com.esri.arcgisruntime.mapping.BasemapStyle;
    import com.esri.arcgisruntime.mapping.Viewpoint;
    import com.esri.arcgisruntime.mapping.view.Graphic;
    import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
    import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
    import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol;
    import com.esri.arcgisruntime.tasks.networkanalysis.Route;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteParameters;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteResult;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteTask;
    import com.esri.arcgisruntime.tasks.networkanalysis.Stop;
    
    import javafx.collections.FXCollections;
    import javafx.collections.ListChangeListener;
    import javafx.collections.ObservableList;
    import javafx.geometry.Point2D;
    import javafx.geometry.Pos;
    import javafx.scene.control.Alert;
    import javafx.scene.control.ListView;
    import javafx.scene.input.MouseButton;
    import java.util.List;
    
    import com.esri.arcgisruntime.ArcGISRuntimeEnvironment;
    import com.esri.arcgisruntime.mapping.ArcGISMap;
    import com.esri.arcgisruntime.mapping.view.MapView;
    
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class App extends Application {
    
      private MapView mapView;
    
      private Graphic routeGraphic;
      private RouteTask routeTask;
      private RouteParameters routeParameters;
      private final ObservableList<Stop> routeStops = FXCollections.observableArrayList();
      private final ListView<String> directionsList = new ListView<>();
    
      public static void main(String[] args) {
        Application.launch(args);
      }
    
      @Override
      public void start(Stage stage) {
    
        // set the title and size of the stage and show it
        stage.setTitle("Find a route and directions tutorial");
        stage.setWidth(800);
        stage.setHeight(700);
        stage.show();
    
        // create a JavaFX scene with a stack pane as the root node
        // and add it to the scene
        StackPane stackPane = new StackPane();
        Scene scene = new Scene(stackPane);
    
        stage.setScene(scene);
    
        // Note: it is not best practice to store API keys in source code.
        // The API key is referenced here for the convenience of this tutorial.
        String yourApiKey = "YOUR_API_KEY";
        ArcGISRuntimeEnvironment.setApiKey(yourApiKey);
    
        // create a MapView to display the map and add it to the stack pane
        mapView = new MapView();
        stackPane.getChildren().add(mapView);
    
        ArcGISMap map = new ArcGISMap(BasemapStyle.ARCGIS_STREETS);
    
        // set the map on the map view
        mapView.setMap(map);
    
        mapView.setViewpoint(new Viewpoint(34.05398, -118.24532, 144447.638572));
    
        directionsList.setMaxSize(400, 250);
        stackPane.getChildren().add(directionsList);
        StackPane.setAlignment(directionsList, Pos.TOP_LEFT);
    
        GraphicsOverlay graphicsOverlay = new GraphicsOverlay();
        mapView.getGraphicsOverlays().add(graphicsOverlay);
    
        routeTask = new RouteTask("https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World");
    
        ListenableFuture<RouteParameters> routeParametersFuture = routeTask.createDefaultParametersAsync();
        routeParametersFuture.addDoneListener(() -> {
          try {
            routeParameters = routeParametersFuture.get();
            routeParameters.setReturnDirections(true);
            directionsList.getItems().add("Click to add two points to the map to find a route.");
    
          } catch (Exception e) {
            Alert alert = new Alert(Alert.AlertType.ERROR, e.toString());
            alert.show();
            e.printStackTrace();
          }
        });
    
        addStopsOnMouseClicked();
    
        routeStops.addListener((ListChangeListener<Stop>) e -> {
          // track the number of stops added to the map, and use it create graphic geometry and symbol text
          int routeStopsSize = routeStops.size();
          // handle user interaction
          if (routeStopsSize == 0) {
            return;
          } else if (routeStopsSize == 1) {
            graphicsOverlay.getGraphics().clear();
            if (!directionsList.getItems().isEmpty())
            directionsList.getItems().clear();
            directionsList.getItems().add("Click to add two points to the map to find a route.");
          }
          // create a blue circle symbol for the stop
          SimpleMarkerSymbol stopMarker = new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, 0xff0000ff, 20);
          // get the stop's geometry
          Geometry routeStopGeometry = routeStops.get(routeStopsSize-1).getGeometry();
    
          graphicsOverlay.getGraphics().add(new Graphic(routeStopGeometry, stopMarker));
    
          if (routeStopsSize == 2) {
            // remove the mouse clicked event if two stops have been added
            mapView.setOnMouseClicked(null);
            routeParameters.setStops(routeStops);
    
            // get the route and display it
            ListenableFuture<RouteResult> routeResultFuture = routeTask.solveRouteAsync(routeParameters);
            routeResultFuture.addDoneListener(() -> {
              try {
                RouteResult result = routeResultFuture.get();
                List<Route> routes = result.getRoutes();
    
                if (!routes.isEmpty()) {
                  Route route = routes.get(0);
                  Geometry shape = route.getRouteGeometry();
                  routeGraphic = new Graphic(shape, new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, 0xff0000ff, 2));
                  graphicsOverlay.getGraphics().add(routeGraphic);
    
                  // get the direction text for each maneuver and display it as a list in the UI
                  route.getDirectionManeuvers().forEach(step -> directionsList.getItems().add(step.getDirectionText()));
                  // reset stops and re-enable mapview interactions once the route task has completed
                  routeStops.clear();
                  addStopsOnMouseClicked();
    
                }
    
              } catch (Exception ex) {
                ex.printStackTrace();
              }
            });
    
          }
    
        });
    
      }
    
      private void addStopsOnMouseClicked() {
        mapView.setOnMouseClicked(event -> {
          if (event.isStillSincePress() && event.getButton() == MouseButton.PRIMARY) {
            Point2D mapPoint = new Point2D(event.getX(), event.getY());
            routeStops.add(new Stop(mapView.screenToLocation(mapPoint)));
          }
        });
      }
    
      /**
       * Stops and releases all resources used in application.
       */
      @Override
      public void stop() {
        if (mapView != null) {
          mapView.dispose();
        }
      }
    
    }
    

Create origin and destination stops

A RouteTask requires at least a single origin and destination stop to find a route. Use a click handler on the mapView to add stops and display them as graphics when the map is clicked.

When a user clicks on the map, a stop will be added to a list of route stops. In this tutorial, the first click will create the origin stop and the second will create the destination stop.

  1. Create a new addStopsOnMouseClicked() method which adds a setOnMouseClicked() listener to the mapView. Convert the clicked JavaFX Point2D to a location Point. Use the point to create a new Stop and add it to the routeStops list.

    App.java
    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
    174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 174 173 172 170 168 166 164 162 160 158 156 154 152 150 148 146 144 142 140 138 136 134 132 130 128 126 124 122 120 118 116 114 112 110 108 106 104 102 100 98 95 92 89 86 83 80 78 76 73 70 67 64 61 59 57 56 55 56 57 58 59 60 61 62 63 64 65 65 65 65 65 65 65 65 65 65 65 65 65
    
    //   Copyright 2020 Esri
    //   Licensed under the Apache License, Version 2.0 (the "License");
    //   you may not use this file except in compliance with the License.
    //   You may obtain a copy of the License at
    //
    //   http://www.apache.org/licenses/LICENSE-2.0
    //
    //   Unless required by applicable law or agreed to in writing, software
    //   distributed under the License is distributed on an "AS IS" BASIS,
    //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    //   See the License for the specific language governing permissions and
    //   limitations under the License.
    
    package com.example.app;
    
    import com.esri.arcgisruntime.concurrent.ListenableFuture;
    import com.esri.arcgisruntime.geometry.Geometry;
    import com.esri.arcgisruntime.mapping.BasemapStyle;
    import com.esri.arcgisruntime.mapping.Viewpoint;
    import com.esri.arcgisruntime.mapping.view.Graphic;
    import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
    import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
    import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol;
    import com.esri.arcgisruntime.tasks.networkanalysis.Route;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteParameters;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteResult;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteTask;
    import com.esri.arcgisruntime.tasks.networkanalysis.Stop;
    
    import javafx.collections.FXCollections;
    import javafx.collections.ListChangeListener;
    import javafx.collections.ObservableList;
    import javafx.geometry.Point2D;
    import javafx.geometry.Pos;
    import javafx.scene.control.Alert;
    import javafx.scene.control.ListView;
    import javafx.scene.input.MouseButton;
    import java.util.List;
    
    import com.esri.arcgisruntime.ArcGISRuntimeEnvironment;
    import com.esri.arcgisruntime.mapping.ArcGISMap;
    import com.esri.arcgisruntime.mapping.view.MapView;
    
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class App extends Application {
    
      private MapView mapView;
    
      private Graphic routeGraphic;
      private RouteTask routeTask;
      private RouteParameters routeParameters;
      private final ObservableList<Stop> routeStops = FXCollections.observableArrayList();
      private final ListView<String> directionsList = new ListView<>();
    
      public static void main(String[] args) {
        Application.launch(args);
      }
    
      @Override
      public void start(Stage stage) {
    
        // set the title and size of the stage and show it
        stage.setTitle("Find a route and directions tutorial");
        stage.setWidth(800);
        stage.setHeight(700);
        stage.show();
    
        // create a JavaFX scene with a stack pane as the root node
        // and add it to the scene
        StackPane stackPane = new StackPane();
        Scene scene = new Scene(stackPane);
    
        stage.setScene(scene);
    
        // Note: it is not best practice to store API keys in source code.
        // The API key is referenced here for the convenience of this tutorial.
        String yourApiKey = "YOUR_API_KEY";
        ArcGISRuntimeEnvironment.setApiKey(yourApiKey);
    
        // create a MapView to display the map and add it to the stack pane
        mapView = new MapView();
        stackPane.getChildren().add(mapView);
    
        ArcGISMap map = new ArcGISMap(BasemapStyle.ARCGIS_STREETS);
    
        // set the map on the map view
        mapView.setMap(map);
    
        mapView.setViewpoint(new Viewpoint(34.05398, -118.24532, 144447.638572));
    
        directionsList.setMaxSize(400, 250);
        stackPane.getChildren().add(directionsList);
        StackPane.setAlignment(directionsList, Pos.TOP_LEFT);
    
        GraphicsOverlay graphicsOverlay = new GraphicsOverlay();
        mapView.getGraphicsOverlays().add(graphicsOverlay);
    
        routeTask = new RouteTask("https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World");
    
        ListenableFuture<RouteParameters> routeParametersFuture = routeTask.createDefaultParametersAsync();
        routeParametersFuture.addDoneListener(() -> {
          try {
            routeParameters = routeParametersFuture.get();
            routeParameters.setReturnDirections(true);
            directionsList.getItems().add("Click to add two points to the map to find a route.");
    
          } catch (Exception e) {
            Alert alert = new Alert(Alert.AlertType.ERROR, e.toString());
            alert.show();
            e.printStackTrace();
          }
        });
    
        addStopsOnMouseClicked();
    
        routeStops.addListener((ListChangeListener<Stop>) e -> {
          // track the number of stops added to the map, and use it create graphic geometry and symbol text
          int routeStopsSize = routeStops.size();
          // handle user interaction
          if (routeStopsSize == 0) {
            return;
          } else if (routeStopsSize == 1) {
            graphicsOverlay.getGraphics().clear();
            if (!directionsList.getItems().isEmpty())
            directionsList.getItems().clear();
            directionsList.getItems().add("Click to add two points to the map to find a route.");
          }
          // create a blue circle symbol for the stop
          SimpleMarkerSymbol stopMarker = new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, 0xff0000ff, 20);
          // get the stop's geometry
          Geometry routeStopGeometry = routeStops.get(routeStopsSize-1).getGeometry();
    
          graphicsOverlay.getGraphics().add(new Graphic(routeStopGeometry, stopMarker));
    
          if (routeStopsSize == 2) {
            // remove the mouse clicked event if two stops have been added
            mapView.setOnMouseClicked(null);
            routeParameters.setStops(routeStops);
    
            // get the route and display it
            ListenableFuture<RouteResult> routeResultFuture = routeTask.solveRouteAsync(routeParameters);
            routeResultFuture.addDoneListener(() -> {
              try {
                RouteResult result = routeResultFuture.get();
                List<Route> routes = result.getRoutes();
    
                if (!routes.isEmpty()) {
                  Route route = routes.get(0);
                  Geometry shape = route.getRouteGeometry();
                  routeGraphic = new Graphic(shape, new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, 0xff0000ff, 2));
                  graphicsOverlay.getGraphics().add(routeGraphic);
    
                  // get the direction text for each maneuver and display it as a list in the UI
                  route.getDirectionManeuvers().forEach(step -> directionsList.getItems().add(step.getDirectionText()));
                  // reset stops and re-enable mapview interactions once the route task has completed
                  routeStops.clear();
                  addStopsOnMouseClicked();
    
                }
    
              } catch (Exception ex) {
                ex.printStackTrace();
              }
            });
    
          }
    
        });
    
      }
    
      private void addStopsOnMouseClicked() {
        mapView.setOnMouseClicked(event -> {
          if (event.isStillSincePress() && event.getButton() == MouseButton.PRIMARY) {
            Point2D mapPoint = new Point2D(event.getX(), event.getY());
            routeStops.add(new Stop(mapView.screenToLocation(mapPoint)));
          }
        });
      }
    
      /**
       * Stops and releases all resources used in application.
       */
      @Override
      public void stop() {
        if (mapView != null) {
          mapView.dispose();
        }
      }
    
    }
    
  2. Call addStopsOnMouseClicked() in the start() method.

    App.java
    Add line.
    111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 112 113 114 115 116 117 118 119 119 117 115 113 111 109 107 105 103 101 99 97 95 93 91 89 87 85 83 81 79 77 75 73 71 69 67 65 63 61 59 57 55 53 51 49 47 45 42 39 36 33 30 27 25 23 20 17 14 11 8 6 4 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
    
    //   Copyright 2020 Esri
    //   Licensed under the Apache License, Version 2.0 (the "License");
    //   you may not use this file except in compliance with the License.
    //   You may obtain a copy of the License at
    //
    //   http://www.apache.org/licenses/LICENSE-2.0
    //
    //   Unless required by applicable law or agreed to in writing, software
    //   distributed under the License is distributed on an "AS IS" BASIS,
    //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    //   See the License for the specific language governing permissions and
    //   limitations under the License.
    
    package com.example.app;
    
    import com.esri.arcgisruntime.concurrent.ListenableFuture;
    import com.esri.arcgisruntime.geometry.Geometry;
    import com.esri.arcgisruntime.mapping.BasemapStyle;
    import com.esri.arcgisruntime.mapping.Viewpoint;
    import com.esri.arcgisruntime.mapping.view.Graphic;
    import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
    import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
    import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol;
    import com.esri.arcgisruntime.tasks.networkanalysis.Route;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteParameters;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteResult;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteTask;
    import com.esri.arcgisruntime.tasks.networkanalysis.Stop;
    
    import javafx.collections.FXCollections;
    import javafx.collections.ListChangeListener;
    import javafx.collections.ObservableList;
    import javafx.geometry.Point2D;
    import javafx.geometry.Pos;
    import javafx.scene.control.Alert;
    import javafx.scene.control.ListView;
    import javafx.scene.input.MouseButton;
    import java.util.List;
    
    import com.esri.arcgisruntime.ArcGISRuntimeEnvironment;
    import com.esri.arcgisruntime.mapping.ArcGISMap;
    import com.esri.arcgisruntime.mapping.view.MapView;
    
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class App extends Application {
    
      private MapView mapView;
    
      private Graphic routeGraphic;
      private RouteTask routeTask;
      private RouteParameters routeParameters;
      private final ObservableList<Stop> routeStops = FXCollections.observableArrayList();
      private final ListView<String> directionsList = new ListView<>();
    
      public static void main(String[] args) {
        Application.launch(args);
      }
    
      @Override
      public void start(Stage stage) {
    
        // set the title and size of the stage and show it
        stage.setTitle("Find a route and directions tutorial");
        stage.setWidth(800);
        stage.setHeight(700);
        stage.show();
    
        // create a JavaFX scene with a stack pane as the root node
        // and add it to the scene
        StackPane stackPane = new StackPane();
        Scene scene = new Scene(stackPane);
    
        stage.setScene(scene);
    
        // Note: it is not best practice to store API keys in source code.
        // The API key is referenced here for the convenience of this tutorial.
        String yourApiKey = "YOUR_API_KEY";
        ArcGISRuntimeEnvironment.setApiKey(yourApiKey);
    
        // create a MapView to display the map and add it to the stack pane
        mapView = new MapView();
        stackPane.getChildren().add(mapView);
    
        ArcGISMap map = new ArcGISMap(BasemapStyle.ARCGIS_STREETS);
    
        // set the map on the map view
        mapView.setMap(map);
    
        mapView.setViewpoint(new Viewpoint(34.05398, -118.24532, 144447.638572));
    
        directionsList.setMaxSize(400, 250);
        stackPane.getChildren().add(directionsList);
        StackPane.setAlignment(directionsList, Pos.TOP_LEFT);
    
        GraphicsOverlay graphicsOverlay = new GraphicsOverlay();
        mapView.getGraphicsOverlays().add(graphicsOverlay);
    
        routeTask = new RouteTask("https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World");
    
        ListenableFuture<RouteParameters> routeParametersFuture = routeTask.createDefaultParametersAsync();
        routeParametersFuture.addDoneListener(() -> {
          try {
            routeParameters = routeParametersFuture.get();
            routeParameters.setReturnDirections(true);
            directionsList.getItems().add("Click to add two points to the map to find a route.");
    
          } catch (Exception e) {
            Alert alert = new Alert(Alert.AlertType.ERROR, e.toString());
            alert.show();
            e.printStackTrace();
          }
        });
    
        addStopsOnMouseClicked();
    
        routeStops.addListener((ListChangeListener<Stop>) e -> {
          // track the number of stops added to the map, and use it create graphic geometry and symbol text
          int routeStopsSize = routeStops.size();
          // handle user interaction
          if (routeStopsSize == 0) {
            return;
          } else if (routeStopsSize == 1) {
            graphicsOverlay.getGraphics().clear();
            if (!directionsList.getItems().isEmpty())
            directionsList.getItems().clear();
            directionsList.getItems().add("Click to add two points to the map to find a route.");
          }
          // create a blue circle symbol for the stop
          SimpleMarkerSymbol stopMarker = new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, 0xff0000ff, 20);
          // get the stop's geometry
          Geometry routeStopGeometry = routeStops.get(routeStopsSize-1).getGeometry();
    
          graphicsOverlay.getGraphics().add(new Graphic(routeStopGeometry, stopMarker));
    
          if (routeStopsSize == 2) {
            // remove the mouse clicked event if two stops have been added
            mapView.setOnMouseClicked(null);
            routeParameters.setStops(routeStops);
    
            // get the route and display it
            ListenableFuture<RouteResult> routeResultFuture = routeTask.solveRouteAsync(routeParameters);
            routeResultFuture.addDoneListener(() -> {
              try {
                RouteResult result = routeResultFuture.get();
                List<Route> routes = result.getRoutes();
    
                if (!routes.isEmpty()) {
                  Route route = routes.get(0);
                  Geometry shape = route.getRouteGeometry();
                  routeGraphic = new Graphic(shape, new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, 0xff0000ff, 2));
                  graphicsOverlay.getGraphics().add(routeGraphic);
    
                  // get the direction text for each maneuver and display it as a list in the UI
                  route.getDirectionManeuvers().forEach(step -> directionsList.getItems().add(step.getDirectionText()));
                  // reset stops and re-enable mapview interactions once the route task has completed
                  routeStops.clear();
                  addStopsOnMouseClicked();
    
                }
    
              } catch (Exception ex) {
                ex.printStackTrace();
              }
            });
    
          }
    
        });
    
      }
    
      private void addStopsOnMouseClicked() {
        mapView.setOnMouseClicked(event -> {
          if (event.isStillSincePress() && event.getButton() == MouseButton.PRIMARY) {
            Point2D mapPoint = new Point2D(event.getX(), event.getY());
            routeStops.add(new Stop(mapView.screenToLocation(mapPoint)));
          }
        });
      }
    
      /**
       * Stops and releases all resources used in application.
       */
      @Override
      public void stop() {
        if (mapView != null) {
          mapView.dispose();
        }
      }
    
    }
    
  3. To display the stops on the map as they are added, add a listener to the routeStops ObservableList and create a new SimpleMarkerSymbol for each Stop. Use the stop's geometry to create a new Graphic and add it to the graphicsOverlay.

    App.java
    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
    118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 139 139 139 139 139 139 139 139 139 139 139 139 139 139 139 139 139 139 138 137 136 135 134 133 133 133 132 131 130 129 128 128 128 129 129 129 129 129 129 129 129 129 129 129 129 129 129 129 129 129 129 129 129 129 129 129 129
    
    //   Copyright 2020 Esri
    //   Licensed under the Apache License, Version 2.0 (the "License");
    //   you may not use this file except in compliance with the License.
    //   You may obtain a copy of the License at
    //
    //   http://www.apache.org/licenses/LICENSE-2.0
    //
    //   Unless required by applicable law or agreed to in writing, software
    //   distributed under the License is distributed on an "AS IS" BASIS,
    //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    //   See the License for the specific language governing permissions and
    //   limitations under the License.
    
    package com.example.app;
    
    import com.esri.arcgisruntime.concurrent.ListenableFuture;
    import com.esri.arcgisruntime.geometry.Geometry;
    import com.esri.arcgisruntime.mapping.BasemapStyle;
    import com.esri.arcgisruntime.mapping.Viewpoint;
    import com.esri.arcgisruntime.mapping.view.Graphic;
    import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
    import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
    import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol;
    import com.esri.arcgisruntime.tasks.networkanalysis.Route;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteParameters;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteResult;
    import com.esri.arcgisruntime.tasks.networkanalysis.RouteTask;
    import com.esri.arcgisruntime.tasks.networkanalysis.Stop;
    
    import javafx.collections.FXCollections;
    import javafx.collections.ListChangeListener;
    import javafx.collections.ObservableList;
    import javafx.geometry.Point2D;
    import javafx.geometry.Pos;
    import javafx.scene.control.Alert;
    import javafx.scene.control.ListView;
    import javafx.scene.input.MouseButton;
    import java.util.List;
    
    import com.esri.arcgisruntime.ArcGISRuntimeEnvironment;
    import com.esri.arcgisruntime.mapping.ArcGISMap;
    import com.esri.arcgisruntime.mapping.view.MapView;
    
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.layout.StackPane;
    import javafx.stage.Stage;
    
    public class App extends Application {
    
      private MapView mapView;
    
      private Graphic routeGraphic;
      private RouteTask routeTask;
      private RouteParameters routeParameters;
      private final ObservableList<Stop> routeStops = FXCollections.observableArrayList();
      private final ListView<String> directionsList = new ListView<>();
    
      public static void main(String[] args) {
        Application.launch(args);
      }
    
      @Override
      public void start(Stage stage) {
    
        // set the title and size of the stage and show it
        stage.setTitle("Find a route and directions tutorial");
        stage.setWidth(800);
        stage.setHeight(700);
        stage.show();
    
        // create a JavaFX scene with a stack pane as the root node
        // and add it to the scene
        StackPane stackPane = new StackPane();
        Scene scene = new Scene(stackPane);
    
        stage.setScene(scene);
    
        // Note: it is not best practice to store API keys in source code.
        // The API key is referenced here for the convenience of this tutorial.
        String yourApiKey = "YOUR_API_KEY";
        ArcGISRuntimeEnvironment.setApiKey(yourApiKey);
    
        // create a MapView to display the map and add it to the stack pane
        mapView = new MapView();
        stackPane.getChildren().add(mapView);
    
        ArcGISMap map = new ArcGISMap(BasemapStyle.ARCGIS_STREETS);
    
        // set the map on the map view
        mapView.setMap(map);
    
        mapView.setViewpoint(new Viewpoint(34.05398, -118.24532, 144447.638572));
    
        directionsList.setMaxSize(400, 250);
        stackPane.getChildren().add(directionsList);
        StackPane.setAlignment(directionsList, Pos.TOP_LEFT);
    
        GraphicsOverlay graphicsOverlay = new GraphicsOverlay();
        mapView.getGraphicsOverlays().add(graphicsOverlay);
    
        routeTask = new RouteTask("https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World");
    
        ListenableFuture<RouteParameters> routeParametersFuture = routeTask.createDefaultParametersAsync();
        routeParametersFuture.addDoneListener(() -> {
          try {
            routeParameters = routeParametersFuture.get();
            routeParameters.setReturnDirections(true);
            directionsList.getItems().add("Click to add two points to the map to find a route.");
    
          } catch (Exception e) {
            Alert alert = new Alert(Alert.AlertType.ERROR, e.toString());
            alert.show();
            e.printStackTrace();
          }
        });
    
        addStopsOnMouseClicked();
    
        routeStops.addListener((ListChangeListener<Stop>) e -> {
          // track the number of stops added to the map, and use it create graphic geometry and symbol text
          int routeStopsSize = routeStops.size();
          // handle user interaction
          if (routeStopsSize == 0) {
            return;
          } else if (routeStopsSize == 1) {
            graphicsOverlay.getGraphics().clear();
            if (!directionsList.getItems().isEmpty())
            directionsList.getItems().clear();
            directionsList.getItems().add("Click to add two points to the map to find a route.");
          }
          // create a blue circle symbol for the stop
          SimpleMarkerSymbol stopMarker = new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, 0xff0000ff, 20);
          // get the stop's geometry
          Geometry routeStopGeometry = routeStops.get(routeStopsSize-1).getGeometry();
    
          graphicsOverlay.getGraphics().add(new Graphic(routeStopGeometry, stopMarker));
    
          if (routeStopsSize == 2) {
            // remove the mouse clicked event if two stops have been added
            mapView.setOnMouseClicked(null);
            routeParameters.setStops(routeStops);
    
            // get the route and display it
            ListenableFuture<RouteResult> routeResultFuture = routeTask.solveRouteAsync(routeParameters);
            routeResultFuture.addDoneListener(() -> {
              try {
                RouteResult result = routeResultFuture.get();
                List<Route> routes = result.getRoutes();
    
                if (!routes.isEmpty()) {
                  Route route = routes.get(0);
                  Geometry shape = route.getRouteGeometry();
                  routeGraphic = new Graphic(shape, new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, 0xff0000ff, 2));
                  graphicsOverlay.getGraphics().add(routeGraphic);