Created
May 12, 2025 09:09
-
-
Save tomastraveltime/12bfd22cfe5435edf9b768dfa41e90d1 to your computer and use it in GitHub Desktop.
Code running two point comparison on https://traveltime.com/accuracy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Client, TravelMode } from '@googlemaps/google-maps-services-js'; | |
import axios from 'axios'; | |
import { Coords, TravelTimeClient } from 'traveltime-api'; | |
const travelTimeSdk = new TravelTimeClient({ | |
apiKey: process.env.TT_APP_KEY || '', | |
applicationId: process.env.TT_APP_ID || '', | |
}); | |
const googleClient = new Client(); | |
const oxfordLocation = { | |
label: 'Oxford, UK', | |
coords: { | |
lat: 51.7520131, | |
lng: -1.2578499, | |
}, | |
country: 'gb' as const, | |
}; | |
const birminghamLocation = { | |
label: 'Birmingham, UK', | |
coords: { | |
lat: 52.4796992, | |
lng: -1.9026911, | |
}, | |
country: 'gb' as const, | |
}; | |
type TwoPointComparisonResponse = Array<{ | |
travelTime: number | |
provider: string | |
}> | |
type Task = (coordsFrom: Coords, coordTo: Coords, date: Date) => Promise<{ provider: string, travelTime: number }> | |
const getNextMidweekNoon = () => { | |
const now = new Date(); | |
const nextMidweek = new Date(now); | |
const targetDay = 3; | |
let daysToAdd = (targetDay - now.getDay() + 7) % 7; | |
if (daysToAdd === 0 && now.getHours() >= 12) { | |
daysToAdd = 7; | |
} | |
nextMidweek.setDate(now.getDate() + daysToAdd); | |
nextMidweek.setHours(12, 0, 0, 0); | |
return nextMidweek; | |
}; | |
async function calculateResponseTime(fnc: () => Promise<number>) { | |
try { | |
const travelTime = await fnc(); | |
return travelTime; | |
} catch (error) { | |
return -1; | |
} | |
} | |
const ttTask: Task = async (coordsFrom, coordsTo, date) => { | |
const fnc = async () => { | |
const res = await travelTimeSdk.routes({ | |
departure_searches: [{ | |
id: 'quick', | |
arrival_location_ids: ['to'], | |
departure_location_id: 'from', | |
departure_time: date.toISOString(), | |
properties: ['travel_time'], | |
transportation: { | |
type: 'driving', | |
}, | |
snapping: { | |
penalty: 'disabled', | |
}, | |
}], | |
locations: [ | |
{ id: 'from', coords: coordsFrom }, | |
{ id: 'to', coords: coordsTo }, | |
], | |
}); | |
return res.results[0].locations[0].properties[0].travel_time ?? -1; | |
}; | |
const travelTime = await calculateResponseTime(fnc); | |
return { | |
travelTime, | |
provider: 'TravelTime', | |
}; | |
}; | |
const googleTask: Task = async (coordsFrom, coordsTo, date) => { | |
const fnc = async () => { | |
const res = await googleClient.distancematrix({ | |
params: { | |
key: process.env.GOOGLE_API_KEY || 'Google API Key', | |
origins: [coordsFrom], | |
destinations: [coordsTo], | |
departure_time: date, | |
mode: TravelMode.driving, | |
}, | |
}); | |
return res.data.rows[0].elements[0].duration.value; | |
}; | |
const travelTime = await calculateResponseTime(fnc); | |
return { | |
travelTime, | |
provider: 'Google', | |
}; | |
}; | |
const tomTomTask: Task = async (coordsFrom, coordsTo, date) => { | |
const fnc = async () => { | |
const res = await axios.get( | |
`https://api.tomtom.com/routing/1/calculateRoute/${coordsFrom.lat},${coordsFrom.lng}:${coordsTo.lat},${coordsTo.lng}/json`, | |
{ | |
params: { | |
key: process.env.TOM_TOM_API_KEY, | |
travelMode: 'car', | |
departAt: date.toISOString(), | |
}, | |
}, | |
); | |
return res.data.routes[0].summary.travelTimeInSeconds; | |
}; | |
const travelTime = await calculateResponseTime(fnc); | |
return { | |
travelTime, | |
provider: 'TomTom', | |
}; | |
}; | |
const hereTask: Task = async (coordsFrom, coordsTo, date) => { | |
const fnc = async () => { | |
const res = await axios.post( | |
`https://matrix.router.hereapi.com/v8/matrix?async=false&apiKey=${process.env.HERE_API_KEY}`, | |
{ | |
origins: [coordsFrom], | |
destinations: [coordsTo], | |
departureTime: date.toISOString(), | |
regionDefinition: { | |
type: 'world', | |
}, | |
transportMode: 'car', | |
}, | |
); | |
return res.data.matrix.travelTimes[0]; | |
}; | |
const travelTime = await calculateResponseTime(fnc); | |
return { | |
travelTime, | |
provider: 'HERE', | |
}; | |
}; | |
const mapBoxTask: Task = async (coordsFrom, coordsTo) => { | |
const fnc = async () => { | |
const res = await axios.get( | |
`https://api.mapbox.com/directions-matrix/v1/mapbox/driving/${coordsFrom.lng},${coordsFrom.lat};${coordsTo.lng},${coordsTo.lat}`, | |
{ | |
params: { | |
access_token: process.env.MAP_BOX_API_KEY, | |
}, | |
}, | |
); | |
return res.data.durations[0][1]; | |
}; | |
const travelTime = await calculateResponseTime(fnc); | |
return { | |
travelTime, | |
provider: 'Mapbox', | |
}; | |
}; | |
let cachedResponse: null | TwoPointComparisonResponse = null; | |
async function run(from: Coords, to: Coords) { | |
try { | |
if (typeof from !== 'object' || !('lat' in from) || !('lng' in from) || typeof to !== 'object' || !('lat' in to) || !('lng' in to)) { | |
throw new Error('Malformed request'); | |
} | |
const isDefaultConfig = from.lat === birminghamLocation.coords.lat && from.lng === birminghamLocation.coords.lng && to.lat === oxfordLocation.coords.lat && to.lng === oxfordLocation.coords.lng; | |
if (isDefaultConfig && cachedResponse) { | |
return cachedResponse; | |
} | |
const date = getNextMidweekNoon(); | |
const params: Parameters<Task> = [from, to, date]; | |
const tasks = Promise.allSettled([ | |
googleTask(...params), | |
ttTask(...params), | |
tomTomTask(...params), | |
hereTask(...params), | |
mapBoxTask(...params), | |
]); | |
const results = (await tasks).filter((_) => _.status === 'fulfilled').map<TwoPointComparisonResponse[number]>((_) => (_ as PromiseFulfilledResult<TwoPointComparisonResponse[number]>).value); | |
if (isDefaultConfig) { | |
cachedResponse = results; | |
setTimeout(() => { | |
cachedResponse = null; | |
}, 1000 * 60 * 60 * 24); | |
} | |
return results; | |
} catch (error) { | |
throw new Error('Error in task execution'); | |
} | |
} | |
run(birminghamLocation.coords, oxfordLocation.coords); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment