Public
Edited
Mar 24, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
agency = ({
uuid: "agency123",
name: "Targomo GmbH",
address: { lng: 13.41533, lat: 52.523299 }
})
Insert cell
Insert cell
transports = dateRange.map((d) => createDayAgent(d))
Insert cell
Insert cell
function createDayAgent(date) {
return {
vehicle: {
uuid: `agent_${date}`,
storeUuid: agency.uuid,
priority: 1,
fixedTravelCosts: (dayjs(date).get("d") - 1) * 60 // each day of the week gets an additional 60s penalty to prioritize earlier dates
},
metadata: {
earliestDepartureTime: `${date}T08:00:00+01:00`, // day start
latestArrivalTime: `${date}T18:00:00+01:00`, // day end
interruptionTimes: [
{
start: `${date}T12:00:00+01:00`, // lunch break start
end: `${date}T13:00:00+01:00` // lunch break end
}
],
start: agency.address, // could also be a home address
endDestination: agency.address // could also be a home address
}
};
}
Insert cell
function createOrder(config) {
const { uuid, storeUuid, lnglat, visitingTimes, color } = config;

const orderConfig = {
uuid,
storeUuid,
priority: 1,
address: {
avgHandlingTime: 3600, // the is the meeting time
lat: lnglat.lat,
lng: lnglat.lng
},
visitingTimes, // if already scheduled, we enforce with strict visiting times
color
};

return orderConfig;
}
Insert cell
timeOffset = (d, key) => dayjs(d[key]).diff(dayjs(dayjs(d[key]).startOf("day"))) // get ms since day start to plot on calendar
Insert cell
Insert cell
config = ({
optimizationTime: 2,
optimizationAlgorithm: "CONSTRAINT_SATISFACTION",
stores: [agency],
orders: allVisits,
transports,
optimizationMetadata: {
geojsonCreation: "ROUTING_SERVICE",
unimprovedWaitingTime: 1,
disableShiftingOfVehicleDeparture: false,
filterOrdersWithWaitingCostHigherThan: 3600,
travelOptions: {
travelType: "car",
elevationEnabled: true,
maxEdgeWeight: 3600,
edgeWeight: "time",
serviceUrl: "https://api.targomo.com/westcentraleurope/",
serviceKey: targomoKey(),
// waitingCostFactors: {
// "0": 0.0,
// "300": 0.5
// }
}
}
})
Insert cell
Insert cell
fullOptimization = {
const rawFetch = await fetch(
`https://api.targomo.com/fleetplanner/v1/api/key-auth/optimizations?key=${targomoKey()}`,
{
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(config)
}
);

return await rawFetch.json();
}
Insert cell
{
const routeGeoJSON = turf.featureCollection(
fullOptimization.tours
.map((d, i) =>
d.featureCollection.features
.filter((f) => f.geometry.type === "LineString")
.map((f) => {
f.properties.tour = i + 1;
f.properties.color = d3.schemeCategory10[9 - i];
return f;
})
)
.flat()
);
map.getSource("route").setData(routeGeoJSON);
return routeGeoJSON;
}
Insert cell
optimization = {
const toursFormat = fullOptimization.tours
.map((d, i) =>
d.tourItems.map((t) => {
const { expectedStartVisit, expectedDeparture, order } = t;
const orderMatch = config.orders.find((o) => o.uuid === order.uuid);
const tourFormat = {
sort: +dayjs(expectedStartVisit),
start: dayjs(expectedStartVisit),
end: dayjs(expectedDeparture),
order: order.uuid,
tour: i + 1,
color: allVisits.find((d) => d.uuid === order.uuid).color
};
return tourFormat;
})
)
.flat()
.sort((a, b) => a.sort < b.sort);

updateCompTable(toursFormat);

return toursFormat;
}
Insert cell
Insert cell
viewof candidateLocation = {
const uuid = "planned1";
const [lat, lng] = [52.54069923102475, 13.206526560634476];
const inp = Inputs.input({ lng, lat, uuid });
const marker = new maplibre.Marker({
draggable: true,
color: d3.schemeCategory10[0]
})
.setLngLat({ lng, lat })
.addTo(map);

marker.on("dragend", () => {
inp.value = { ...marker.getLngLat(), uuid };
inp.dispatchEvent(new Event("input", { bubbles: true }));
});
return inp;
}
Insert cell
currentmarkers = []
Insert cell
{
currentmarkers.forEach((marker) => marker.remove());
for (const item of calendarItems) {
const marker = new maplibre.Marker({
color: item.color
})
.setLngLat(item.geolocation)
.addTo(map);
currentmarkers.push(marker);
}
}
Insert cell
calendarItemsAll = [
{
id: "scheduled1",
location: "Im Marienpark 23, 12107 Berlin, Germany",
geolocation: { lat: 52.438082, lng: 13.36822 },
color: d3.schemeCategory10[1],
start: "2023-03-21T09:00:00+01:00",
end: "2023-03-21T10:00:00+01:00"
},
{
id: "scheduled2",
location: "Potsdamer Str. 182, 10783 Berlin, Germany",
geolocation: { lat: 52.493704, lng: 13.360434 },
color: d3.schemeCategory10[2],
start: "2023-03-21T10:30:00+01:00",
end: "2023-03-21T11:30:00+01:00"
},
{
id: "scheduled3",
location: "Jesse-Owens-Allee, 14053 Berlin, Germany",
geolocation: { lat: 52.511138, lng: 13.238996 },
color: d3.schemeCategory10[3],
start: "2023-03-21T13:00:00+01:00",
end: "2023-03-21T14:00:00+01:00"
},
{
id: "scheduled4",
location: "Lehrter Str. 57, 10557 Berlin, Germany",
geolocation: { lat: 52.533042, lng: 13.359729 },
color: d3.schemeCategory10[4],
start: "2023-03-21T16:00:00+01:00",
end: "2023-03-21T17:00:00+01:00"
},
{
id: "scheduled5",
location: "An d. Wuhlheide 263, 12555 Berlin, Germany",
geolocation: { lat: 52.457349, lng: 13.568059 },
color: d3.schemeCategory10[5],
start: "2023-03-22T10:00:00+01:00",
end: "2023-03-22T11:00:00+01:00"
},
{
id: "scheduled6",
location: "Rennbahnstraße 45, 13086 Berlin, Germany",
geolocation: { lat: 52.563628, lng: 13.455974 },
color: d3.schemeCategory10[6],
start: "2023-03-22T15:30:00+01:00",
end: "2023-03-22T16:30:00+01:00"
}
]
Insert cell
Insert cell
{
const bbox = turf.bbox(
turf.featureCollection([
...calendarItems.map((d) =>
turf.point([d.geolocation.lng, d.geolocation.lat])
),
turf.point([agency.address.lng, agency.address.lat]),
turf.point([candidateLocation.lng, candidateLocation.lat])
])
);
map.fitBounds(bbox, { padding: 50 });
}
Insert cell
function updateCompTable(optimized) {
mutable compTable = optimized
.map((d) => {
const { start, end, order, tour, sort } = d;
return {
tour,
meeting: order,
sort,
start: start.format("YYYY-MM-DD HH:mm"),
end: end.format("YYYY-MM-DD HH:mm")
};
})
.sort((a, b) => a.sort - b.sort)
.map((d) => {
const { sort, ...fields } = d;
return fields;
});
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
dateRange = {
const start = dayjs("2023-03-20T00:00:00");
const days = Array.from({ length: 5 }).map((d, i) =>
start.add(i, "day").format("YYYY-MM-DD")
);
return days;
}
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more