Hi All,
The requirement is solve a route with best sequence by the given stops. However, when solve with the service "https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World", the result doesn't make sense for me.
This is the original sequence stops and route.
This green route is the response which findBestSequence is true.
The red route is the expectation result.
Attach is the code implemented by ArcGIS Map SDKs for JavaScript version 4.27
<!DOCTYPE html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" />
<title>Network - Find Best Sequence</title>
<style>
html,
body,
#viewDiv { padding: 0; margin: 0; height: 100%; width: 100%; };
.buttons { position: absolute; top: 50px; right: 50px; z-index: 1; }
.best-sequence { top: 50px; right: 50px; z-index: 1; };
.optimize-layers { top: 100px; right: 50px; z-index: 1; };
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.27/esri/themes/light/main.css">
<style>
/* overwrite esri default css */
.esri-view .esri-view-surface--inset-outline:focus::after {
outline: none;
};
</style>
<script src="https://js.arcgis.com/4.27/"></script>
<script>
let _findBestSequence = null, _toggleOptimizeLayers = null;
require([
"esri/config", "esri/intl", "esri/Map", "esri/views/MapView", "esri/geometry/Point", "esri/geometry/Polyline",
"esri/symbols/SimpleLineSymbol", "esri/Graphic", "esri/layers/GraphicsLayer", "esri/rest/support/FeatureSet",
"esri/symbols/PictureMarkerSymbol", "esri/rest/route", "esri/rest/support/RouteParameters"],
function(
esriConfig, esriIntl, Map, MapView, Point, Polyline,
SimpleLineSymbol, Graphic, GraphicsLayer, FeatureSet,
PictureMarkerSymbol, route, RouteParameters) {
esriConfig.apiKey = "<API_KEY_WITH_OPTIMIZED_ROUTING>";
esriIntl.setLocale("en");
let _map, _stopLayer, _routeLayer, _bestStopLayer, _bestRouteLayer;
let _stop1, _stop2, _stop3, _stop4, _stop5, _stop6, _stop7, _stop8, _stop9;
const CURB_APPROACH = {
EITHER_SIDE: 0,
RIGHT_SIDE: 1,
LEFT_SIDE: 2,
NO_U_TURN: 3
};
const initMap = () =>
{
_map = new Map({
basemap: "arcgis-streets" // Basemap layer service
});
const CREEK_VIEW_PLZ = [-73.924596, 42.784273];
const CONSTRAINT_EXTENT = {
type: "extent",
xmin: -180,
ymin: -70,
xmax: 180,
ymax: 70
};
const view = new MapView({
map: _map,
center: CREEK_VIEW_PLZ,
constraints: {
geometry: CONSTRAINT_EXTENT,
minZoom: 3,
maxZoom: 18
},
zoom: 13,
container: "viewDiv"
});
_stopLayer = new GraphicsLayer({ id: "stop-layer" });
_routeLayer = new GraphicsLayer({ id: "route-layer" });
_bestStopLayer = new GraphicsLayer({ id: "best-stop-layer" });
_bestRouteLayer = new GraphicsLayer({ id: "best-route-layer" });
_map.addMany([_routeLayer, _stopLayer, _bestRouteLayer, _bestStopLayer]);
};
const stopSymbol = (sequence, fillColor, textColor) =>
{
const svgString = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" width="28" height="28">' +
'<g>' +
`<circle r="12" cy="14" cx="14" stroke-linecap="butt" stroke="#000000" stroke-width="2" fill="${fillColor}" />` +
`<text text-anchor="middle" font-size="12" x="50%" y="50%" dy=".3em" stroke-width="0" fill="${textColor}" >${sequence}</text>` +
'</g>' +
'</svg >';
const svg = `data:image/svg+xml;charset=UTF-8;base64,${btoa(svgString)}`;
return new PictureMarkerSymbol({ url: svg, height: 28, width: 28 });
};
const createStopGraphic = (location, sequence, curbApproach) =>
{
const { longitude, latitude } = location;
const geometry = new Point({
type: "point",
x: longitude,
y: latitude
});
const symbol = stopSymbol(sequence, "#0000FF", "#FFFFFF");
const attributes = {
CurbApproach: curbApproach,
Name: sequence,
Sequence: sequence
};
const graphic = new Graphic({ geometry, symbol, attributes });
return graphic;
};
const addStops = () =>
{
const location1 = { longitude: -73.946891, latitude: 42.808323 };
const location2 = { longitude: -73.938998, latitude: 42.783614 };
const location3 = { longitude: -73.937482, latitude: 42.77529 };
const location4 = { longitude: -73.921461, latitude: 42.773114 };
const location5 = { longitude: -73.900918, latitude: 42.774755 };
const location6 = { longitude: -73.932357, latitude: 42.764845 };
const location7 = { longitude: -73.904294, latitude: 42.788485 };
const location8 = { longitude: -73.897857, latitude: 42.781619 };
const location9 = { longitude: -73.89135, latitude: 42.763158 };
_stop1 = createStopGraphic(location1, 1, CURB_APPROACH.RIGHT_SIDE);
_stop2 = createStopGraphic(location2, 2, CURB_APPROACH.RIGHT_SIDE);
_stop3 = createStopGraphic(location3, 3, CURB_APPROACH.RIGHT_SIDE);
_stop4 = createStopGraphic(location4, 4, CURB_APPROACH.RIGHT_SIDE);
_stop5 = createStopGraphic(location5, 5, CURB_APPROACH.RIGHT_SIDE);
_stop6 = createStopGraphic(location6, 6, CURB_APPROACH.RIGHT_SIDE);
_stop7 = createStopGraphic(location7, 7, CURB_APPROACH.RIGHT_SIDE);
_stop8 = createStopGraphic(location8, 8, CURB_APPROACH.RIGHT_SIDE);
_stop9 = createStopGraphic(location9, 9, CURB_APPROACH.RIGHT_SIDE);
_stopLayer.addMany([_stop1, _stop2, _stop3, _stop4, _stop5, _stop6, _stop7, _stop8, _stop9]);
};
const calculateRoute = async (parameters) =>
{
const url = "https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World";
const defaultParameters = {
directionsLengthUnits: "kilometers",
findBestSequence: false,
ignoreInvalidLocations: false,
impedanceAttribute: null,
outputGeometryPrecision: 0,
outputGeometryPrecisionUnits: "feet",
outputLines: "true-shape",
outSpatialReference: "102100",
pointBarriers: null,
polylineBarriers: null,
polygonBarriers: null,
preserveFirstStop: true,
preserveLastStop: true,
restrictionAttributes: [],
restrictUTurns: "at-dead-ends-only",
returnBarriers: false,
returnDirections: true,
returnPolygonBarriers: false,
returnPolylineBarriers: false,
returnPointBarriers: false,
returnTraversedEdges: false,
returnTraversedJunctions: false,
returnTraversedTurns: false,
returnRoutes: true,
returnStops: true,
returnZ: false,
startTime: new Date()
};
const params = Object.assign({}, defaultParameters, parameters);
const routeParameters = new RouteParameters(params);
return route.solve(url, routeParameters).then((response) => {
results = response?.routeResults[0];
return results;
}).catch((error) => {
console.log(error);
});
};
const addRoutes = (routeResults, routeColor, routeLayer) =>
{
const route = routeResults.route;
route.symbol = {
type: "simple-line",
style: "solid",
color: routeColor,
width: 5
};
routeLayer.removeAll();
routeLayer.add(route);
};
const addBestStops = (routeResults) =>
{
const stops = routeResults.stops;
stops.forEach(item =>
{
item.symbol = stopSymbol(item.attributes.Sequence, "#00FF00", "#000000");
});
_bestStopLayer.addMany(stops);
}
_findBestSequence = () =>
{
if (_bestRouteLayer.graphics.length > 0)
{
return;
}
// THE MOCKUP DATA IS CALCULATED BY route-api.arcgis.com
// const routeResults = _getMockupRouteResult();
// if (routeResults)
// {
// addRoutes(routeResults, "#00FF00", _bestRouteLayer);
// addBestStops(routeResults);
// return;
//}
const featureSet = new FeatureSet({ features: [_stop1, _stop2, _stop3, _stop4, _stop5, _stop6, _stop7, _stop8, _stop9]});
const parameters = {
stops: featureSet,
findBestSequence: true,
};
calculateRoute(parameters).then((routeResults) =>
{
addRoutes(routeResults, "#00FF00", _bestRouteLayer);
addBestStops(routeResults);
});
};
_toggleOptimizeLayers = () =>
{
_bestRouteLayer.visible = !_bestRouteLayer.visible;
_bestStopLayer.visible = !_bestStopLayer.visible;
};
const _getMockupRouteResult = () =>
{
const routeResultString = `73.88902999999993,42.76705000000004],[-73.88870999999995,42.766770000000065],[-73.88854999999995,42.76663000000008],[-73.88834999999995,42.766440000000046],[-73.88830999999993,42.76640000000003],[-73.88828999999998,42.76638000000003],[-73.88818999999995,42.76628000000005],[-73.88808999999998,42.76619000000005],[-73.88774999999998,42.765870000000064],[-73.88760999999994,42.76574000000005],[-73.88750999999996,42.76565000000005],[-73.88741999999996,42.765570000000025],[-73.88697999999994,42.76517000000007],[-73.88711999999998,42.76508000000007],[-73.88724999999994,42.76499000000007],[-73.88742999999994,42.76487000000003],[-73.88757999999996,42.764770000000055],[-73.88771999999994,42.76469000000003],[-73.88783999999998,42.76461000000006],[-73.88880999999998,42.76400000000007],[-73.88968999999997,42.76352000000003],[-73.89104508699995,42.762671209000075]]]},"symbol":null,"attributes":{"ObjectID":1,"Name":"1 - 9","FirstStopID":1,"LastStopID":9,"StopCount":9,"StartTime":1695679888215,"EndTime":1695682127523,"StartTimeUTC":1695694288215,"EndTimeUTC":1695696527523,"Total_TravelTime":37.32144021498387,"Total_Miles":14.305202978168186,"Total_Kilometers":23.02205399019508,"Shape_Length":0.23989589944373005},"popupTemplate":null},"routeName":"1 - 9","stops":[{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.94689099999994,"y":42.80832300000003},"symbol":null,"attributes":{"ObjectID":1,"Name":"1","RouteName":null,"Sequence":1,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":null,"DepartCurbApproach":1,"ArriveTime":1695679888215,"DepartTime":1695679888215,"ArriveTimeUTC":1695694288215,"DepartTimeUTC":1695694288215,"LocationType":0,"SourceID":1,"SourceOID":63147648,"PosAlong":0.34237244765307046,"SideOfEdge":2,"CurbApproach":1,"Status":0,"SnapX":-73.94672033928657,"SnapY":42.80822427066172,"SnapZ":0,"DistanceToNetworkInMeters":17.749139007493312,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":0,"Cumul_Miles":0,"Cumul_Kilometers":0},"popupTemplate":null},{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.93899799999997,"y":42.78361400000006},"symbol":null,"attributes":{"ObjectID":2,"Name":"2","RouteName":null,"Sequence":4,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":1,"DepartCurbApproach":1,"ArriveTime":1695680734292,"DepartTime":1695680734292,"ArriveTimeUTC":1695695134292,"DepartTimeUTC":1695695134292,"LocationType":0,"SourceID":1,"SourceOID":63146091,"PosAlong":0.5636337747364589,"SideOfEdge":2,"CurbApproach":1,"Status":0,"SnapX":-73.93886363519862,"SnapY":42.78365781460919,"SnapZ":0,"DistanceToNetworkInMeters":12.012903327686413,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":14.101278520945046,"Cumul_Miles":6.0195674111523445,"Cumul_Kilometers":9.687540583087975},"popupTemplate":null},{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.93748199999999,"y":42.77529000000004},"symbol":null,"attributes":{"ObjectID":3,"Name":"3","RouteName":null,"Sequence":3,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":1,"DepartCurbApproach":1,"ArriveTime":1695680526217,"DepartTime":1695680526217,"ArriveTimeUTC":1695694926217,"DepartTimeUTC":1695694926217,"LocationType":0,"SourceID":1,"SourceOID":63138337,"PosAlong":0.45030927837121815,"SideOfEdge":1,"CurbApproach":1,"Status":0,"SnapX":-73.9374952783505,"SnapY":42.77526012371141,"SnapZ":0,"DistanceToNetworkInMeters":3.4972226978186014,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":10.633365513763083,"Cumul_Miles":5.046930037515004,"Cumul_Kilometers":8.122276568847795},"popupTemplate":null},{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.92146099999997,"y":42.77311400000008},"symbol":null,"attributes":{"ObjectID":4,"Name":"4","RouteName":null,"Sequence":5,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":1,"DepartCurbApproach":1,"ArriveTime":1695681105343,"DepartTime":1695681105343,"ArriveTimeUTC":1695695505343,"DepartTimeUTC":1695695505343,"LocationType":0,"SourceID":1,"SourceOID":63138761,"PosAlong":0.4422169742862514,"SideOfEdge":2,"CurbApproach":1,"Status":0,"SnapX":-73.92093689562441,"SnapY":42.77326540793081,"SnapZ":0,"DistanceToNetworkInMeters":46.023911694552666,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":20.285097158798607,"Cumul_Miles":8.172199575981388,"Cumul_Kilometers":13.151826698408081},"popupTemplate":null},{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.90091799999993,"y":42.77475500000003},"symbol":null,"attributes":{"ObjectID":5,"Name":"5","RouteName":null,"Sequence":6,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":1,"DepartCurbApproach":1,"ArriveTime":1695681424473,"DepartTime":1695681424473,"ArriveTimeUTC":1695695824473,"DepartTimeUTC":1695695824473,"LocationType":0,"SourceID":1,"SourceOID":63139130,"PosAlong":0.8245841679039545,"SideOfEdge":1,"CurbApproach":1,"Status":0,"SnapX":-73.90102890910511,"SnapY":42.77492064346879,"SnapZ":0,"DistanceToNetworkInMeters":20.54614900282448,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":25.603939080683475,"Cumul_Miles":9.868476490319022,"Cumul_Kilometers":15.881658860608237},"popupTemplate":null},{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.93235699999997,"y":42.76484500000004},"symbol":null,"attributes":{"ObjectID":6,"Name":"6","RouteName":null,"Sequence":2,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":1,"DepartCurbApproach":1,"ArriveTime":1695680344685,"DepartTime":1695680344685,"ArriveTimeUTC":1695694744685,"DepartTimeUTC":1695694744685,"LocationType":0,"SourceID":1,"SourceOID":63138157,"PosAlong":0.1916291835017726,"SideOfEdge":2,"CurbApproach":1,"Status":0,"SnapX":-73.93245806896545,"SnapY":42.76460917241386,"SnapZ":0,"DistanceToNetworkInMeters":27.52091696371127,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":7.607832029575178,"Cumul_Miles":4.0238698180457675,"Cumul_Kilometers":6.475802534674298},"popupTemplate":null},{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.90429399999994,"y":42.78848500000004},"symbol":null,"attributes":{"ObjectID":7,"Name":"7","RouteName":null,"Sequence":8,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":1,"DepartCurbApproach":1,"ArriveTime":1695681710194,"DepartTime":1695681710194,"ArriveTimeUTC":1695696110194,"DepartTimeUTC":1695696110194,"LocationType":0,"SourceID":1,"SourceOID":63149967,"PosAlong":0.24651097243960704,"SideOfEdge":1,"CurbApproach":1,"Status":0,"SnapX":-73.90429443322716,"SnapY":42.788485495521385,"SnapZ":0,"DistanceToNetworkInMeters":0,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":30.36594730808806,"Cumul_Miles":11.373253179390383,"Cumul_Kilometers":18.303373785743467},"popupTemplate":null},{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.89785699999999,"y":42.781619000000035},"symbol":null,"attributes":{"ObjectID":8,"Name":"8","RouteName":null,"Sequence":7,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":1,"DepartCurbApproach":1,"ArriveTime":1695681550048,"DepartTime":1695681550048,"ArriveTimeUTC":1695695950048,"DepartTimeUTC":1695695950048,"LocationType":0,"SourceID":1,"SourceOID":63149749,"PosAlong":0.4030693159607203,"SideOfEdge":1,"CurbApproach":1,"Status":0,"SnapX":-73.89795730532335,"SnapY":42.78176045622528,"SnapZ":0,"DistanceToNetworkInMeters":17.751683431579593,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":27.69685045415899,"Cumul_Miles":10.536587654594042,"Cumul_Kilometers":16.956892682908844},"popupTemplate":null},{"aggregateGeometries":null,"geometry":{"spatialReference":{"latestWkid":4326,"wkid":4326},"x":-73.89134999999999,"y":42.76315800000003},"symbol":null,"attributes":{"ObjectID":9,"Name":"9","RouteName":null,"Sequence":9,"TimeWindowStart":null,"TimeWindowEnd":null,"ArriveCurbApproach":1,"DepartCurbApproach":null,"ArriveTime":1695682127523,"DepartTime":1695682127523,"ArriveTimeUTC":1695696527523,"DepartTimeUTC":1695696527523,"LocationType":0,"SourceID":1,"SourceOID":63138941,"PosAlong":0.2554466608713769,"SideOfEdge":2,"CurbApproach":1,"Status":7,"SnapX":-73.89104508707719,"SnapY":42.76267120919345,"SnapZ":0,"DistanceToNetworkInMeters":59.64467303334708,"Attr_Minutes":0,"Attr_TravelTime":0,"Attr_Miles":0,"Attr_Kilometers":0,"Attr_TimeAt1KPH":0,"Attr_WalkTime":0,"Attr_TruckMinutes":0,"Attr_TruckTravelTime":0,"Cumul_TravelTime":37.32144021498387,"Cumul_Miles":14.305202978168186,"Cumul_Kilometers":23.02205399019508},"popupTemplate":null}]}'`;
return JSON.parse(routeResultString);
};
initMap();
addStops();
const featureSet = new FeatureSet({ features: [_stop1, _stop2, _stop3, _stop4, _stop5, _stop6, _stop7, _stop8, _stop9]});
const parameters = {
stops: featureSet
};
calculateRoute(parameters).then((routeResults) =>
{
addRoutes(routeResults, "#0000FF", _routeLayer);
});
});
const findBestSequence = () => _findBestSequence();
const toggleOptimizeLayers = () => _toggleOptimizeLayers();
</script>
</head>
<body>
<div class="buttons">
<button class="best-sequence" onclick="findBestSequence()">Find Best Sequence</button>
<button class="optimize-layers" onclick="toggleOptimizeLayers()">Show/Hide Best Sequence Layers</button>
</div>
<div id="viewDiv"></div>
</body>
</html>