Created
August 4, 2017 15:07
-
-
Save i8ramin/b2b55fdd2ad3b2f455e6e7f78198b025 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
<script> | |
/** | |
* Percent page viewed plugin | |
* | |
* Usage: | |
* bamPercentPageViewed.init({ option : 'value' }); | |
* | |
* Options: | |
* trackDelay : 1500 - The delay (in ms) before a scroll position is considered stable (reduce scroll bouncers) | |
* percentInterval : 10 - Track every 10% the page is scrolled | Default: 25 | |
* callback : function(data){ console.log(data); } - The callback for the previous page scroll position | |
* | |
*/ | |
(function(bamPercentPageViewed) { | |
/** | |
* Throttle function borrowed from: | |
* Underscore.js 1.5.2 | |
* http://underscorejs.org | |
* (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors | |
* Underscore may be freely distributed under the MIT license. | |
*/ | |
function throttle(t,n){var e,u,l,r=null,a=0,i=function(){a=new Date,r=null,l=t.apply(e,u)};return function(){var o=new Date;a||(a=o);var c=n-(o-a);return e=this,u=arguments,c>0?r||(r=setTimeout(i,c)):(clearTimeout(r),r=null,a=o,l=t.apply(e,u)),l}} | |
// Array.prototype.find Polyfill cause IE sucks | |
Array.prototype.find||Object.defineProperty(Array.prototype,"find",{value:function(t){if(null==this)throw new TypeError('"this" is null or not defined');var r=Object(this),e=r.length>>>0;if("function"!=typeof t)throw new TypeError("predicate must be a function");for(var n=arguments[1],o=0;e>o;){var i=r[o];if(t.call(n,i,o,r))return i;o++}return void 0}}); | |
// Default options | |
var defaultOptions = { | |
trackDelay: 1500, | |
percentInterval: 25, | |
callback: null, | |
}; | |
// Last scroll action | |
var lastScroll = null; | |
// FIXME: make this thing a proper class that has access to this.options; | |
var options = {}; | |
// Keep track of already scrolled depths, so we don't trigger event again | |
var scrollDepths = []; | |
/** | |
* Initialize the tracker and pass in optional overrides | |
* @param object | |
* @return bamPercentPageViewed | |
*/ | |
bamPercentPageViewed.init = function(opts) { | |
// Options | |
if (typeof(opts) == typeof({})) { | |
for (var property in opts) { | |
if (options.hasOwnProperty(property)) { | |
defaultOptions[property] = opts[property]; | |
} | |
} | |
} | |
// FIXME | |
options = opts; | |
// Get the amount of screen currently in view | |
processScroll(); | |
// Do not break the chain | |
return this; | |
}; | |
/** | |
* Page scroll percentage | |
* @return int | |
*/ | |
function scrollPercent() { | |
return Math.ceil(((scrollPosition() + viewportHeight()) / pageHeight()) * 100); | |
} | |
/** | |
* Page height | |
* @return int | |
*/ | |
function pageHeight() { | |
return Math.max( | |
document.body.scrollHeight, document.documentElement.scrollHeight, | |
document.body.offsetHeight, document.documentElement.offsetHeight, | |
document.body.clientHeight, document.documentElement.clientHeight | |
); | |
} | |
/** | |
* Viewport height | |
* @return int | |
*/ | |
function viewportHeight() { | |
return (window.innerHeight || document.documentElement.clientHeight || document.getElementsByTagName('body')[0].clientHeight || 0); | |
} | |
/** | |
* Current window scroll position | |
* @return int | |
*/ | |
function scrollPosition() { | |
return (window.pageYOffset || document.documentElement.scrollTop) - (document.documentElement.clientTop || 0); | |
} | |
/** | |
* Scroll percentage by interval | |
* @return int | |
*/ | |
function scrollPercentByInterval(percentInterval) { | |
var multiplier = parseInt(scrollPercent() / (parseInt(percentInterval) - 0.0000000001)); | |
return (multiplier * parseInt(percentInterval)); | |
} | |
/** | |
* Process scroll | |
*/ | |
function processScroll() { | |
var depth; | |
var trackedDepth; | |
var path = document.location.pathname; | |
var url = document.location.href; | |
if (lastScroll === null || (new Date().getTime()) - lastScroll >= parseInt(defaultOptions.trackDelay)) { | |
depth = scrollPercentByInterval(defaultOptions.percentInterval); | |
trackedDepth = scrollDepths.find(function (entry) { | |
return (entry.path === path) && (entry.depth === depth); | |
}); | |
if (!trackedDepth && (depth > 0) && typeof(options.callback) === 'function') { | |
scrollDepths.push({ | |
path: path, | |
depth: depth | |
}); | |
options.callback.call(window, { | |
depth: depth, | |
url: url, | |
path: path, | |
scrollPosition: scrollPosition(), | |
viewportHeight: viewportHeight(), | |
pageHeight: pageHeight(), | |
}); | |
} | |
} | |
} | |
/** | |
* Listen for throttled window scroll event | |
*/ | |
window.onscroll = throttle(function() { | |
lastScroll = new Date().getTime(); | |
setTimeout(processScroll, parseInt(defaultOptions.trackDelay) + 25); | |
}, 100); | |
}(window.bamPercentPageViewed = window.bamPercentPageViewed || {})); | |
</script> | |
<script> | |
// init the plugin | |
bamPercentPageViewed.init({ | |
trackDelay: 1000, | |
callback: function (data) { | |
window.analytics.track('Scroll Depth', data); | |
} | |
}); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment