Skip to content

Instantly share code, notes, and snippets.

@chrahunt
Created May 30, 2016 05:56
Show Gist options
  • Save chrahunt/f7d6eb3371db433bb73ff6f4f07c4792 to your computer and use it in GitHub Desktop.
Save chrahunt/f7d6eb3371db433bb73ff6f4f07c4792 to your computer and use it in GitHub Desktop.
Maps API in Google Sheets
var Properties = PropertiesService.getScriptProperties();
/**
* Return rate-limited function under specified delay.
* @param {Function} fn The function to wrap.
* @param {string} domain The domain under which to apply the delay.
* @param {number} delay Time (in ms) between successive calls.
* @return {Function} The function to call.
*/
function RateLimited(fn, domain, delay) {
var key = domain + "-lastcall";
return function() {
var now = Date.now();
var lock = LockService.getDocumentLock();
lock.waitLock(5000);
var last_call = Properties.getProperty(key);
var delay_exec = 0;
if (last_call === null) {
Properties.setProperty(key, now);
} else {
var next = +last_call + delay;
if (next > now) {
delay_exec = next - now;
Properties.setProperty(key, next);
} else {
Properties.setProperty(key, now);
}
}
lock.releaseLock();
if (delay_exec) {
Utilities.sleep(delay_exec);
}
return fn.apply(null, arguments);
};
}
// Safe, rate-limited methods.
var Safe = {
getDrivingTime: RateLimited(getDrivingTime, "maps", 2000)
};
// "hash" arbitrary number of string arguments to use as a key.
function hash() {
var out = "";
for (var i = 0; i < arguments.length; i++) {
out += arguments[i];
}
return out;
}
/**
* Get driving time given origin, destination, and arrival time.
* @private
* @param {string} origin
* @param {string} dest
* @param {Date} arrival
* @return {number?} The driving time in seconds or null if no route was found.
*/
function getDrivingTime(origin, dest, arrival) {
var directions = Maps.newDirectionFinder()
.setOrigin(origin)
.setDestination(dest)
.setMode(Maps.DirectionFinder.Mode.DRIVING)
.setArrive(arrival)
.getDirections();
if (directions && directions.routes.length > 0) {
var sum = directions.routes[0].legs.map(function (leg) {
return leg.duration.value;
}).reduce(function (sum, leg) {
return sum + leg;
});
return sum;
} else {
return null;
}
}
/**
* Calculates the time it takes to travel between two locations.
*
* @param {(string|range)} start The start address.
* @param {string} end The end address.
* @return {string} The driving time.
* @customfunction
*/
function drivingTime(start, end) {
// Handle range in start.
if (start.map) {
return start.map(function (s) { return drivingTime(s, end); });
}
var startWorkDay = new Date(2016, 5, 23, 9, 30);
var cache = CacheService.getDocumentCache();
var key = hash(start, end, startWorkDay);
var val = cache.get(key);
// Clean up bad data.
if (isNaN(val)) {
cache.remove(key);
val = null;
}
// Cache miss.
if (val === null) {
val = Safe.getDrivingTime(start, end, startWorkDay);
if (!isNaN(val) && typeof val == "number") {
cache.put(key, val);
} else {
return "Not found";
}
}
return Math.ceil(val / 60) + "m";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment