In this tutorial you will learn how our advanced Route Optimization App is implemented. The app optimizes specific transports (single depot location, customer locations with pickups and deliveries) and displays the optimal routes for each vehicle on the map. To focus on the core principles, only basic error handling has been implemented. The aim of the code examples in the tutorial is to illustrate the use of the PTV Developer Route Optimization API.
Prerequisites
- JavaScript knowledge, including up-to-date knowledge of ES6 features.
- Basic knowledge of JavaScript asynchronous programming using Promises.
- HTML page for displaying PTVs Raster Map with Leaflet. For help, please visit this tutorial on Raster Maps.
How to use this tutorial
This tutorial illustrates step by step how to implement depot based transports in the PTV Developer Route Optimization API with JavaScript.
Getting started
- Request an API key:
- Register and login at myptv.com
- Activate PTV Developer
- Create your API key
- Download an editor such as Visual Studio Code or Atom which work with HTML and JavaScript.
- You can find more details of requests and responses in the reference manual.
- Detailed information about the PTV Developer Route Optimization API is also available in the Quick Start.
- For more information, please visit the Leaflet reference documentation.
Create the JavaScript code
Create a new JavaScript file and reference it in the HTML page for display in the map.
Create an optimization plan
The first step is to add the code below and replace the string "YOUR_API_KEY" with your PTV Developer API key if this has not already been done.
The plan to be optimized consists of locations (single depot location, customer locations), relevant transports and used vehicles. In addition, you can specify the quantity of pickups and deliveries to be transported at the individual customer locations, as well as the capacity of the specific vehicle profiles.
Part of the result is the generated unique planId, which is used for all following API requests.
const api_key = "YOUR_API_KEY";
// Always add the API key to request headers
const applyAPIKey = (configuration) => ({
...configuration,
headers: {
"apiKey": api_key,
...configuration ? { ...configuration.headers } : {}
}
});
const createOptimizationPlan = () => {
const vehicles = [];
const numberOfVehicles = 2; // Set number of vehicles to use
const vehicleProfile = "EUR_CAR"; // Set profile for the vehicles
const capacity = 25; // Set the capacity of each vehicle
for (let i = 1; i <= numberOfVehicles; i++) {
vehicles.push({
id: "Vehicle " + i,
profile: vehicleProfile,
startLocationId: "Depot1", // The location id from which the vehicle is to start
endLocationId: "Depot1", // The location id from which the vehicle is to end
capacities: [capacity]
});
}
const restrictions = {
... // Set restrictions, if you have any
};
const planToBeOptimized = {
locations: [...], // Specified locations
transports: [...], // Specified transports
vehicles,
restrictions
};
return fetch(
"https://api.myptv.com/routeoptimization/v1/plans",
applyAPIKey({
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(planToBeOptimized)
})
)
.then(response => response.ok ? response.json() : console.error(response))
};
You can use the PTV Developer Geocoding API to find locations by a given search text. For more information to this API, please visit the reference documentation.
const searchText = "Berlin";
fetch(
`https://api.myptv.com/geocoding/v1/locations/by-text?searchText=${searchText}`,
applyAPIKey()
)
.then(response => response.json())
.then({ locations } => console.log(locations));
Start the optimization process for that plan
After creating a plan, start the optimization process based on the planId.
const startOptimization = (planId) =>
fetch(
`https://api.myptv.com/routeoptimization/v1/plans/${planId}/operation/optimization`,
applyAPIKey({
method: "POST",
headers: {
"Content-Type": "application/json"
}
})
).then(response => response.ok ? true : console.error(response));
Check the progress of the optimization process
Retrieve the optimization process status to check if the optimized plan is finished.
const getOptimizationProgress = (planId) =>
fetch(
`https://api.myptv.com/routeoptimization/v1/plans/${planId}/operation`,
applyAPIKey()
).then(response => response.ok ? response.json() : console.error(response));
Get the optimized plan
After the optimization process has been successfully completed (status = SUCCEEDED) the plan is updated internally and you can request the optimized plan.
const getOptimizedPlan = (planId) =>
fetch(
`https://api.myptv.com/routeoptimization/v1/plans/${planId}`,
applyAPIKey()
).then(response => response.ok ? response.json() : console.error(response));
Put the optimization process together
Now you can put the separate steps of the optimization process together to optimize specified transports.
const optimizeTransports = async () => {
const plan = await createOptimizationPlan(); // Create an optimization plan
if (!plan) return;
const startSuccessful = await startOptimization(plan.id); // Start the optimization
if (!startSuccessful) return;
const interval = setInterval( async () => {
const progress = await getOptimizationProgress(plan.id); // Get optimization progress
if (!progress) return clearInterval(interval);
// Only if the optimization has been finished and successful
if (progress.status === "SUCCEEDED") {
clearInterval(interval);
const optimizedPlan = await getOptimizedPlan(plan.id); // Get optimized plan
if (!optimizedPlan) return;
console.log(optimizedPlan);
}
}, 500);
};
Display optimized routes on the map
To display the routes given by the optimized plan as a Leaflet Polyline on the map, retrieve the optimized plan and add two more functions.
const map = new L.Map(...); // Your Leaflet map instance
const addPolylineToMap = (coordinates) => {
const randomColor = "#" + (Math.random() * 0xFFFFFF << 0).toString(16).padStart(6, "0"); // Choose a random color
const polyline = L.polyline(coordinates, {color: randomColor});
polyline.addTo(map);
map.fitBounds(polyline.getBounds()); // Fit map to added polyline
}
const drawRoutes = (optimizedPlan) => {
const { locations, routes } = optimizedPlan;
routes.forEach(route => {
const locationIds = route.stops.map(stop => stop.locationId);
// Extract the coordinates
const coordinates = locationIds.map(locationId => {
const location = locations.find(location => location.id === locationId)
return [location.latitude, location.longitude];
});
addPolylineToMap(coordinates);
});
};
// Adapt this existing function
const optimizeTransports = async () => {
...
const interval = setInterval( async () => {
...
if (progress.status === "SUCCEEDED") {
...
console.log(optimizedPlan);
drawRoutes(optimizedPlan); // Call the function to draw the routes
}
}, 500);
};