Skip to content

Instantly share code, notes, and snippets.

@kotarok
Last active October 4, 2016 15:28
Show Gist options
  • Save kotarok/f6628beb91168a72fd02 to your computer and use it in GitHub Desktop.
Save kotarok/f6628beb91168a72fd02 to your computer and use it in GitHub Desktop.
Watch if the given element is in viewport and fires 'inview' and 'outview' event respectively.
var watchInview = function(el) {
// Get most closest element which has scrollbar.
var scrollContainer = getAncestors(el).find(function(el) {
return el.scrollHeight > el.offsetHeight || el.scrollWidth > el.offsetWidth;
});
el.scrollContainer =
(scrollContainer instanceof HTMLBodyElement)? window: scrollContainer;
el.scrollListener_ = function() {
var reveal = getReveal(el, el.scrollContainer);
var isInview = (reveal.x && reveal.y);
if (isInview && !el.wasInview) {
el.dispatchEvent(new Event('inview'));
el.wasInview = true;
} else if (!isInview && el.wasInview) {
el.dispatchEvent(new Event('outview'));
el.wasInview = false;
}
};
el.scrollContainer.addEventListener('scroll', el.scrollListener_);
if (el !== window) { // To initialise elements already in revealed.
el.scrollContainer.scrollTop = 1;
el.scrollContainer.scrollTop = 0;
}
};
var unwatchInview = function(el) {
el.scrollContainer.removeEventListener('scroll', el.scrollListener_);
};
var getAncestors = function(el) {
var els = [];
while ((el = getParent(el))) els.push(el);
return els;
};
var getParent = function(el) {
var pel = el.parentNode;
return (pel instanceof HTMLElement)? pel: undefined;
};
var getReveal = function(el, container) {
var cRect = (container === window || undefined)? {
left: 0, width: window.innerWidth,
top: 0, height: window.innerHeight,
}: container.getBoundingClientRect();
var eRect = el.getBoundingClientRect();
/**
* Calculate reveal ratio of element to container by given params
* @private
* @return {Number} Ratio of revealed ration in between 0 and 1.
*/
var calcReveal_ = function(start, end, axis, result) {
revStart = (cRect[axis] + cRect[start] - eRect[start]) / eRect[axis];
revEnd = (eRect[end] - cRect[start]) / eRect[axis];
result = Math.min(revStart, revEnd);
return (result > 1)? 1: (result < 0)? 0: result;
};
return {
x: calcReveal_('left', 'right', 'width'),
y: calcReveal_('top', 'bottom', 'height')
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment