Created
May 30, 2016 05:56
-
-
Save chrahunt/f7d6eb3371db433bb73ff6f4f07c4792 to your computer and use it in GitHub Desktop.
Maps API in Google Sheets
This file contains 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
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