// The API Key provided is restricted to JSFiddle website
// Get your own API Key on https://myprojects.geoapify.com
const myAPIKey = "6dc7fb95a3b246cfa0f3bcef5ce9ed9a";
// create a map object
const map = new maplibregl.Map({
container: 'my-map',
center: [7.438684130809055,
46.95097255],
zoom: 12,
style: `https://maps.geoapify.com/v1/styles/klokantech-basic/style.json?apiKey=${myAPIKey}`,
});
map.addControl(new maplibregl.NavigationControl());
// this object describes the task
const busRouteOptimizationInput = {
"mode": "drive",
"agents": [
{
"start_location": [
7.4474023,
46.9467234
],
"end_location": [
7.438684130809055,
46.95097255
],
"pickup_capacity": 4
},
{
"start_location": [
7.4378570072965395,
46.9486723
],
"end_location": [
7.438684130809055,
46.95097255
],
"pickup_capacity": 4
},
{
"start_location": [
7.4527263,
46.9491169
],
"end_location": [
7.438684130809055,
46.95097255
],
"pickup_capacity": 4
},
{
"start_location": [
7.465467108707118,
46.942533
],
"end_location": [
7.438684130809055,
46.95097255
],
"pickup_capacity": 7
},
{
"start_location": [
7.462132898387589,
46.94558515
],
"end_location": [
7.438684130809055,
46.95097255
],
"pickup_capacity": 4
}
],
"jobs": [
{
"location": [
7.450493219453888,
46.9399672
],
"duration": 300,
"pickup_amount": 1
},
{
"location": [
7.456512380644636,
46.940145599999994
],
"duration": 300,
"pickup_amount": 1
},
{
"location": [
7.455119358248906,
46.94004565
],
"duration": 300,
"pickup_amount": 1
},
{
"location": [
7.478417531953476,
46.94478645
],
"duration": 300,
"pickup_amount": 2
},
{
"location": [
7.362979500000002,
46.968168399999996
],
"duration": 300,
"pickup_amount": 1
},
{
"location": [
7.424495152468452,
46.9386158
],
"duration": 300,
"pickup_amount": 1
},
{
"location": [
7.432850439795348,
46.94266075
],
"duration": 300,
"pickup_amount": 1
},
{
"location": [
7.450407245461376,
46.9489173
],
"duration": 300,
"pickup_amount": 2
},
{
"location": [
7.488243448294424,
46.95675175
],
"duration": 300,
"pickup_amount": 1
},
{
"location": [
7.468804378881785,
46.9444164
],
"duration": 300,
"pickup_amount": 1
},
{
"location": [
7.4350012289914105,
46.9542386
],
"duration": 300,
"pickup_amount": 1
},
{
"location": [
7.450849213110402,
46.9399815
],
"duration": 300,
"pickup_amount": 1
},
{
"location": [
7.471101544294104,
46.9516166
],
"duration": 300,
"pickup_amount": 2
},
{
"location": [
7.457033330316839,
46.94910515
],
"duration": 300,
"pickup_amount": 1
},
{
"location": [
7.426033718917774,
46.94642235
],
"duration": 300,
"pickup_amount": 2
},
{
"location": [
7.399196917764858,
46.94673205
],
"duration": 300,
"pickup_amount": 1
},
{
"location": [
7.433453011915322,
46.95080195
],
"duration": 300,
"pickup_amount": 1
},
{
"location": [
7.399111720254629,
46.94071865
],
"duration": 300,
"pickup_amount": 1
},
{
"location": [
7.453808876666665,
46.947940200000005
],
"duration": 300,
"pickup_amount": 2
},
{
"location": [
7.453189190665297,
46.94737785
],
"duration": 300,
"pickup_amount": 1
}
]
};
// colors
const colors = ["#ff4d4d", "#1a8cff", "#00cc66", "#b300b3", "#e6b800", "#ff3385",
"#0039e6", "#408000", "#ffa31a", "#990073", "#cccc00", "#cc5200", "#6666ff", "#009999"
];
map.on('load', () => {
visualizeLocations(busRouteOptimizationInput, map);
// solve route optimization task
fetch(`https://api.geoapify.com/v1/routeplanner?apiKey=${myAPIKey}`, {
method: 'post',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(busRouteOptimizationInput)
}).then(res => res.json())
.then(res => {
notifyAboutIssues(res);
res.features.forEach((feature, index) => visualizeAgentWaypoints(feature, colors[index]));
res.features.forEach((feature, index) => visualizeAgentRoute(feature, colors[index], index));
});
});
function visualizeLocations(routeOptimizationTask, map) {
// collect unique locations
const locationMap = {};
routeOptimizationTask.jobs.forEach(job => {
const locationStr = `${job.location[1]} ${job.location[0]}`;
locationMap[locationStr] = job.location;
});
// visualize lication as a layer
const geoJSONObj = {
"type": "FeatureCollection",
"features": Object.keys(locationMap).map(locationKey => {
return {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": locationMap[locationKey]
}
}
})
};
map.addSource('locations', {
type: 'geojson',
data: geoJSONObj
});
map.addLayer({
'id': 'locations',
'type': 'circle',
'source': 'locations',
'paint': {
'circle-radius': 5,
'circle-color': "#ff9933",
'circle-stroke-width': 1,
'circle-stroke-color': '#994d00',
}
});
}
function notifyAboutIssues(result) {
if (result.properties.issues) {
alert(`The solution has issues: ${Object.keys(result.properties.issues).join(', ')}`);
}
}
function visualizeAgentWaypoints(feature, color) {
const waypoints = feature.properties.waypoints
.map((waypoint, index) => {
return {
"type": "Feature",
"properties": {
index: index + 1
},
"geometry": {
"type": "Point",
"coordinates": waypoint.location
}
}
});
// create points source + layer
map.addSource(`agent-${feature.properties.agent_index}-waypoints`, {
type: 'geojson',
data: {
"type": "FeatureCollection",
"features": waypoints
}
});
map.addLayer({
'id': `agent-${feature.properties.agent_index}-waypoints-circle`,
'type': 'circle',
'source': `agent-${feature.properties.agent_index}-waypoints`,
'paint': {
'circle-radius': 10,
'circle-color': color,
'circle-stroke-width': 1,
'circle-stroke-color': "rgba(0,0,0,0.2)"
}
});
map.addLayer({
'id': `agent-${feature.properties.agent_index}-waypoints-text`,
'type': 'symbol',
'source': `agent-${feature.properties.agent_index}-waypoints`,
'layout': {
"text-field": '{index}',
'text-allow-overlap': false,
"text-font": [
"Roboto", "Helvetica Neue", "sans-serif"
],
"text-size": 12
},
'paint': {
"text-color": "rgba(255, 255, 255, 1)"
}
});
}
function visualizeAgentRoute(feature, color, index) {
const lineWidth = 7 - index;
const shift = -2 + index * 2;
// generate a route and visualite it
const waypoints = feature.properties.waypoints.map(waypoint => waypoint.location[1] + ',' + waypoint.location[0]).join('|');
fetch(`https://api.geoapify.com/v1/routing?waypoints=${waypoints}&mode=drive&apiKey=${myAPIKey}`)
.then(res => res.json())
.then(res => {
map.addSource(`agent-${feature.properties.agent_index}-route`, {
type: 'geojson',
data: res
});
map.addLayer({
'id': `agent-${feature.properties.agent_index}-route`,
'type': 'line',
'source': `agent-${feature.properties.agent_index}-route`,
'layout': {
'line-cap': "round",
'line-join': "round"
},
'paint': {
'line-color': color,
'line-width': lineWidth,
'line-translate': [shift, shift]
}
});
map.moveLayer(`agent-${feature.properties.agent_index}-waypoints-circle`);
map.moveLayer(`agent-${feature.properties.agent_index}-waypoints-text`);
});
}