diff --git a/example.html b/example.html index bb25f4f..3a9caf8 100644 --- a/example.html +++ b/example.html @@ -1,44 +1,55 @@ - - - GeolocationThrottle Example - - -

GeolocationThrottle Example

- -

- This example will print the lat/lng of the current location, at most once every 5 seconds. -

- - -

- -
- - - - - - - \ No newline at end of file + + + GeolocationThrottle Example + + + +

GeolocationThrottle Example

+

+ This example will print the lat/lng of the current location, at most once every 5 seconds. + +
+
+ + +

+
+ + + + + diff --git a/geolocation-throttle-es5.js b/geolocation-throttle-es5.js new file mode 100644 index 0000000..6bdfb3c --- /dev/null +++ b/geolocation-throttle-es5.js @@ -0,0 +1,78 @@ +(function (window) { + window.GeolocationThrottle = { + // a mapping of watchId => timeoutId that can be used to clear position watching + _timeoutIds: {}, + + /** + * Works just like navigator.geolocation.watchPosition, but adds one extra argument + * (throttleTime) to the options object, and makes sure that only one location callback + * is made per throttleTime timespan. + * + * Assumes that the browser supports navigator.geolocation, so one should still check for + * that. The single purpose of this lib is to throttle the location callbacks. + */ + watchPosition: function (callback, errorCallback, options) { + var throttleTime = (!options ? 0 : options.throttleTime || 0); + var bufferedArguments = null; + var lastCall = null; + var timeoutId = null; + var watchId = null; + + watchId = navigator.geolocation.watchPosition(function () { + // update bufferedArguments + bufferedArguments = arguments; + + if (!lastCall) { + //console.log("calling immediately initially"); + lastCall = new Date(); + callback.apply(this, arguments); + } else if (!timeoutId) { + // check if we've already passed the buffer time, in which case + // we'll call the callback immediately + if (new Date() - lastCall > throttleTime) { + //console.log("calling immediately since time has already passed"); + lastCall = new Date(); + callback.apply(this, arguments); + } else { + // if not enough time has passed since the last callback, we'll schedule + // a callback in the future + var that = this; + //console.log("call scheduled"); + timeoutId = setTimeout(function () { + //console.log("Call"); + lastCall = new Date(); + callback.apply(that, bufferedArguments); + + timeoutId = null; + window.GeolocationThrottle._timeoutIds[watchId] = null; + }, throttleTime - (new Date() - lastCall)); + + // we store the timeout id so that we can clear the timeout if clearWatch + // is called before the setTimeout fires + window.GeolocationThrottle._timeoutIds[watchId] = timeoutId; + } + } else { + // we already have a scheduled call + //console.log("skipping call"); + } + }, errorCallback, options); + return watchId; + }, + + /** + * Calls navigator.geolocation.clearWatch for the given watchId, but also + * clears any timeout that has been set up by GeolocationThrottle to make + * sure that no more callback for this watchId is called. + */ + clearWatch: function (watchId) { + navigator.geolocation.clearWatch(watchId); + + // if there's a scheduled watch position callback we'll clear it + var timeoutId = window.GeolocationThrottle._timeoutIds[watchId]; + if (timeoutId) { + clearTimeout(timeoutId); + window.GeolocationThrottle._timeoutIds[watchId] = null; + } + } + }; +})(window); diff --git a/geolocation-throttle-es6.js b/geolocation-throttle-es6.js new file mode 100644 index 0000000..c847faa --- /dev/null +++ b/geolocation-throttle-es6.js @@ -0,0 +1,74 @@ +{ + window.GeolocationThrottle = { + // a mapping of watchId => timeoutId that can be used to clear position watching + _timeoutIds: new Map(), + + /** + * Works just like navigator.geolocation.watchPosition, but adds one extra argument + * (throttleTime) to the options object, and makes sure that only one location callback + * is made per throttleTime timespan. + * + * Assumes that the browser supports navigator.geolocation, so one should still check for + * that. The single purpose of this lib is to throttle the location callbacks. + */ + watchPosition: (callback, errorCallback, options) => { + const throttleTime = (!options ? 0 : options.throttleTime || 0); + let lastCall = null; + let timeoutId = null; + + const watchId = navigator.geolocation.watchPosition(function () { + if (!lastCall) { + //console.log("calling immediately initially"); + lastCall = new Date(); + callback.apply(this, arguments); + } else if (!timeoutId) { + // check if we've already passed the buffer time, in which case + // we'll call the callback immediately + if (new Date() - lastCall > throttleTime) { + //console.log("calling immediately since time has already passed"); + lastCall = new Date(); + callback.apply(this, arguments); + } else { + // if not enough time has passed since the last callback, we'll schedule + // a callback in the future + //console.log("call scheduled"); + + const timeout = throttleTime - (new Date() - lastCall); + timeoutId = setTimeout(() => { + //console.log("Call"); + lastCall = new Date(); + callback.apply(this, arguments); + + timeoutId = null; + window.GeolocationThrottle._timeoutIds.delete(watchId); + }, timeout); + + // we store the timeout id so that we can clear the timeout if clearWatch + // is called before the setTimeout fires + window.GeolocationThrottle._timeoutIds.set(watchId, timeoutId); + } + } else { + // we already have a scheduled call + //console.log("skipping call"); + } + }, errorCallback, options); + return watchId; + }, + + /** + * Calls navigator.geolocation.clearWatch for the given watchId, but also + * clears any timeout that has been set up by GeolocationThrottle to make + * sure that no more callback for this watchId is called. + */ + clearWatch: watchId => { + navigator.geolocation.clearWatch(watchId); + + // if there's a scheduled watch position callback we'll clear it + const timeoutId = window.GeolocationThrottle._timeoutIds.get(watchId); + if (timeoutId) { + clearTimeout(timeoutId); + window.GeolocationThrottle._timeoutIds.delete(watchId); + } + } + }; +} diff --git a/geolocation-throttle.js b/geolocation-throttle.js deleted file mode 100644 index 58a0236..0000000 --- a/geolocation-throttle.js +++ /dev/null @@ -1,78 +0,0 @@ -(function(window) { - window.GeolocationThrottle = { - // a mapping of watchId => timeoutId that can be used to clear position watching - _timeoutIds: {}, - - /** - * Works just like navigator.geolocation.watchPosition, but adds one extra argument - * (throttleTime) to the options object, and makes sure that only one location callback - * is made per throttleTime timespan. - * - * Assumes that the browser supports navigator.geolocation, so one should still check for - * that. The single purpose of this lib is to throttle the location callbacks. - */ - watchPosition: function(callback, errorCallback, options) { - var throttleTime = (!options ? 0 : options.throttleTime || 0); - var bufferedArguments = null; - var lastCall = null; - var timeoutId = null; - var watchId = null; - - watchId = navigator.geolocation.watchPosition(function() { - // update bufferedArguments - bufferedArguments = arguments; - - if (!lastCall) { - //console.log("calling immediately initially"); - lastCall = new Date(); - callback.apply(this, arguments); - } else if (!timeoutId) { - // check if we've already passed the buffer time, in which case - // we'll call the callback immediately - if (new Date()-lastCall > throttleTime) { - //console.log("calling immediately since time has already passed"); - lastCall = new Date(); - callback.apply(this, arguments); - } else { - // if not enough time has passed since the last callback, we'll schedule - // a callback in the future - var that = this; - //console.log("call scheduled"); - timeoutId = setTimeout(function() { - //console.log("Call"); - lastCall = new Date(); - callback.apply(that, bufferedArguments); - - timeoutId = null; - window.GeolocationThrottle._timeoutIds[watchId] = null; - }, throttleTime - (new Date()-lastCall)); - - // we store the timeout id so that we can clear the timeout if clearWatch - // is called before the setTimeout fires - window.GeolocationThrottle._timeoutIds[watchId] = timeoutId; - } - } else { - // we already have a scheduled call - //console.log("skipping call"); - } - }, errorCallback, options); - return watchId; - }, - - /** - * Calls navigator.geolocation.clearWatch for the given watchId, but also - * clears any timeout that has been set up by GeolocationThrottle to make - * sure that no more callback for this watchId is called. - */ - clearWatch: function(watchId) { - navigator.geolocation.clearWatch(watchId); - - // if there's a scheduled watch position callback we'll clear it - var timeoutId = window.GeolocationThrottle._timeoutIds[watchId]; - if (timeoutId) { - clearTimeout(timeoutId); - window.GeolocationThrottle._timeoutIds[watchId] = null; - } - } - }; -})(window);