Skip to content

Instantly share code, notes, and snippets.

@paulmkoch
Created May 15, 2014 16:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paulmkoch/1c88c9a2afd5e3cfd47a to your computer and use it in GitHub Desktop.
Save paulmkoch/1c88c9a2afd5e3cfd47a to your computer and use it in GitHub Desktop.
Scroll Tracker
// Replace CATEGORY and ACTION with the names that you desire for your events.
<script type="text/javascript">
/**
* @name jQuery.trackScrolls
* @desc Watch for scrolling past certain positions.
*
* @example:
*
* $(".track").trackScrolls({
* onLandmark: function($el, progress) {
* _gaq.push('_trackEvent', $el.attr("data-track-scrolls"), progress);
* }
* });
*
* @require jQuery
*/
(function() {
/* Extracted from Underscore */
var throttle = function(func, wait, options) {
var context, args, result;
var timeout = null;
var previous = 0;
options || (options = {});
var later = function() {
previous = options.leading === false ? 0 : new Date;
timeout = null;
result = func.apply(context, args);
};
return function() {
var now = new Date;
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0) {
clearTimeout(timeout);
timeout = null;
previous = now;
result = func.apply(context, args);
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
};
var triggerNearestLandmark = function(el, scroll, options) {
var $el = $(el);
var info = $el.data("trackScrolls") || { current: -1, shown: false }
var progress = 1;
// Already tracked past 100%? Skip this element
if (info.current >= 1) return;
// Height using complete box model (without margin)
var height = $el.outerHeight(false);
// Offset from the top of the page to the bottom of the element
var top = height + $el.offset().top;
while (progress > 0) {
if (progress > info.current && top - height * (1 - progress) <= scroll) {
if (!info.shown) {
options.onShow($el, info);
info.shown = true;
}
info.current = progress;
options.onLandmark($el, progress * 100, info);
break;
}
progress -= 0.25;
}
// Remember how far we've tracked, so that we don't repeat
// events.
$el.data("trackScrolls", info);
};
$.fn.trackScrolls = function(options) {
var settings = $.extend({
onShow: function() {},
onLandmark: function() {}
}, options);
var trackers = $(this);
var isFrame = window.location !== window.parent.location;
var $window = $(isFrame? window.parent : window);
var $frame = $(window.frameElement);
$window.on('scroll.trackScrolls', throttle(function() {
var scroll = $window.scrollTop() + $window.height();
// If we're dealing with an iFrame then offset by the frame's position
// on the page.
if (isFrame) {
scroll -= $frame.offset().top;
}
trackers.each(function() {
triggerNearestLandmark(this, scroll, settings);
});
}, 10));
}
}(window.jQuery));
$(document).ready(function() {
$("body").trackScrolls({
onLandmark: function($el, progress) {
_gaq.push(['_trackEvent', 'CATEGORY', 'ACTION', progress.toString(), 0, true]);
}
});
})
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment