diff --git a/src/script/util.js b/src/script/util.js index b20ee338..03861ba8 100644 --- a/src/script/util.js +++ b/src/script/util.js @@ -123,6 +123,70 @@ gxp.util = { return a.href; }, + /** api: function[throttle] + * :arg func: ``Function`` + * :arg wait: ``Integer`` + * :return: ``Function`` + * + * Returns a function, that, when invoked, will only be triggered at + * most once during a given window of time. + */ + throttle: (function() { + + // Underscore.js 1.3.3 + // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. + // Underscore is freely distributable under the MIT license. + // Portions of Underscore are inspired or borrowed from Prototype, + // Oliver Steele's Functional, and John Resig's Micro-Templating. + // For all details and documentation: + // http://documentcloud.github.com/underscore + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. If `immediate` is passed, trigger the function on the + // leading edge, instead of the trailing. + var debounce = function(func, wait, immediate) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + if (!immediate) func.apply(context, args); + }; + if (immediate && !timeout) func.apply(context, args); + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }; + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. + var throttle = function(func, wait) { + var context, args, timeout, throttling, more, result; + var whenDone = debounce(function(){ more = throttling = false; }, wait); + return function() { + context = this; args = arguments; + var later = function() { + timeout = null; + if (more) func.apply(context, args); + whenDone(); + }; + if (!timeout) timeout = setTimeout(later, wait); + if (throttling) { + more = true; + } else { + result = func.apply(context, args); + } + whenDone(); + throttling = true; + return result; + }; + }; + return function(func, wait) { + return throttle(func, wait); + }; + })(), + /** api: function[md5] * :arg data: ``String`` * :returns: ``String`` md5 hash diff --git a/src/script/widgets/TimelinePanel.js b/src/script/widgets/TimelinePanel.js index 4647fe1d..94a0e2c5 100644 --- a/src/script/widgets/TimelinePanel.js +++ b/src/script/widgets/TimelinePanel.js @@ -158,6 +158,12 @@ window.Timeline && window.SimileAjax && (function() { */ gxp.TimelinePanel = Ext.extend(Ext.Panel, { + /** api: config[scrollInterval] + * ``Integer`` The Simile scroll event listener will only be handled + * upon every scrollInterval milliseconds. Defaults to 500. + */ + scrollInterval: 500, + /** api: config[featureEditor] * ``gxp.plugins.FeatureEditor`` */ @@ -806,7 +812,7 @@ gxp.TimelinePanel = Ext.extend(Ext.Panel, { // since the bands are linked we need to listen to one band only this._silent = true; this.timeline.getBand(0).addOnScrollListener( - this.setPlaybackCenter.createDelegate(this) + gxp.util.throttle(this.setPlaybackCenter.createDelegate(this), this.scrollInterval) ); },