;(function (root) {
function throttle (fn, threshhold, scope) {
threshhold || (threshhold = 100)
var last,
deferTimer
return function () {
var context = scope || this
var now = +(new Date())
var args = arguments
if (last && now < last + threshhold) {
clearTimeout(deferTimer)
deferTimer = setTimeout(function () {
last = now
fn.apply(context, args)
}, threshhold)
} else {
last = now
fn.apply(context, args)
}
}
}
function hasClass (el, name) {
return new RegExp(' ' + name + ' ').test(' ' + el.className + ' ')
}
function addClass (el, name) {
if (!hasClass(el, name)) {
el.className += ' ' + name
}
return el
}
function removeClass (el, name) {
var newClass = ' ' + el.className.replace(/[\t\r\n]/g, ' ') + ' '
if (hasClass(el, name)) {
while (newClass.indexOf(' ' + name + ' ') >= 0) {
newClass = newClass.replace(' ' + name + ' ', ' ')
}
el.className = newClass.replace(/^\s+|\s+$/g, '')
}
return el
}
function removeEvent (el, name, fn) {
if (el.removeEventListener) {
return el.removeEventListener(name, fn)
} else if (el.detachEvent) {
return el.detachEvent('on' + name, fn)
}
}
function addEvent (el, name, fn) {
if (el.addEventListener) {
return el.addEventListener(name, fn, false)
} else if (el.attachEvent) {
return el.attachEvent('on' + name, fn)
}
}
function getScrollTop () {
if (typeof window.pageYOffset !== 'undefined') {
return window.pageYOffset
} else {
var b = document.body
var d = document.documentElement
d = d.clientHeight ? d : b
return d.scrollTop
}
}
function isInView (obj) {
var winTop = getScrollTop()
var winBottom = winTop + window.innerHeight
var objTop = obj.getBoundingClientRect().top + window.scrollY
var objBottom = objTop + obj.offsetHeight
var offset = 0
if ((objTop <= winBottom + offset) && (objBottom >= winTop)) {
return true
}
return false
}
/**
* @desc Create an InView instance.
*
* @class
* @func InView
* @param {HTMLElement} element - element to detect when scrolled to view
* @param {scrollCallback} scrollCallback - callback function fired on scroll event
* @return {HTMLElement} - element
*
* @example
* var el = document.querySelector('.item');
*
* var InView = InView(el, function(isInView, data) {
* if (isInView) {
* console.log('in view');
* } else {
* if (data.windowScrollTop - (data.elementOffsetTop - data.inViewHeight) > data.inViewHeight) {
* console.log('not in view (scroll up)');
* } else {
* console.log('not in view (scroll down)');
* }
* }
* });
*/
function InView (el, callback) {
var _this = this
if (!(_this instanceof InView)) {
return new InView(el, callback)
}
_this.el = el
_this.callback = callback.bind(_this)
_this.destroy = function () {}
if (!el) {
return _this
}
var isDestroyed = false
var check = function check (e) {
if (isDestroyed) return false
var params = {
windowScrollTop: getScrollTop(),
elementOffsetTop: _this.el.offsetTop,
inViewHeight: window.innerHeight,
elementOffsetTopInViewHeight: window.innerHeight - (getScrollTop() - (_this.el.offsetTop - window.innerHeight))
}
if (isInView(_this.el)) {
addClass(_this.el, 'inview')
_this.callback.call(_this, true, params)
} else {
removeClass(_this.el, 'inview')
_this.callback.call(_this, false, params)
}
}
var throttledCheck = throttle(check, 100)
addEvent(window, 'scroll', throttledCheck)
_this.destroy = function () {
isDestroyed = true
removeEvent(window, 'scroll', throttledCheck)
}
throttledCheck()
return _this
}
/**
* @desc InView callback
*
* @callback scrollCallback
* @param {boolean} isInView - is in view
* @param {object} data - scroll data
* @param {number} data.windowScrollTop - scrolled amount
* @param {number} data.elementOffsetTop - element top offset
* @param {number} data.inViewHeight - height of visible area
* @param {number} data.elementOffsetTopInViewHeight - element top offset relative to height of visible area
*/
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = InView
}
exports.InView = InView
} else {
root.InView = InView
}
})(window);