Skip to content

Instantly share code, notes, and snippets.

@jtangelder
Last active August 29, 2015 13:59
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jtangelder/10842041 to your computer and use it in GitHub Desktop.
Save jtangelder/10842041 to your computer and use it in GitHub Desktop.
inview.js
/**
* triggers a callback when an element gets into the viewport
* uses a little bit of jQuery. elements auto receive the class `inview`
*
* the threshold parameter is on scale from 0 to 1 of the height.
* 0 means it triggers directly, 1 means it must be full visible
*
* @example
* // images needs to be 50% in view
* inview.register("img", .5, function(item, inview_state) {
* console.log(item, inview_state);
* });
*/
/**
* requires the frameEvents lib, makes the events run at 60fps
* https://github.com/jtangelder/frame-events
* make sure you also have a requestAnimationFrame polyfill included.
* see the github page of frame-events for a link
*/
var frameEvents = require('./frame-events');
var jQuery = require('jquery');
// holds all registered inview elements
var inview_elements = [];
/**
* collects the reflow vars on scroll
* @returns {{scrollY: Number}}
*/
function collectOnScrollData() {
return {
scrollY: window.scrollY,
winHeight: window.innerHeight
};
}
/**
* raf handler
* @method inViewElements
* @param [ev]
* @param scrollData
*/
function inViewElements(ev, scrollData) {
var item, i, inview, threshold,
scrollY = scrollData.scrollY,
win_height = scrollData.winHeight;
// now update the classes
for(i = 0; i < inview_elements.length; i++) {
item = inview_elements[i];
// item must be already x% inview
threshold = (item.height * item.threshold);
inview = (
(scrollY + (win_height - threshold) > item.top) &&
(scrollY < item.top + item.height - threshold)
);
item.element.toggleClass('inview', inview);
if(item.callback) {
item.callback(inview, item, scrollData);
}
}
}
/**
* update positions and run inview check
* @method updateInViewElements
* @param [ev]
* @param [scrollData]
*/
function updateInViewElements(ev, scrollData) {
var i, item;
// collect offset, this will cause one reflow
for(i = 0; i < inview_elements.length; i++) {
item = inview_elements[i];
item.top = item.element.offset().top;
item.height = item.element.outerHeight();
}
inViewElements(ev, scrollData || collectOnScrollData());
}
/**
* update in the next animation frame
* @method rafUpdate
*/
function rafUpdate() {
requestAnimationFrame(function() {
updateInViewElements();
});
}
frameEvents.on(window, "load", updateInViewElements, collectOnScrollData);
frameEvents.on(window, "resize", updateInViewElements, collectOnScrollData);
frameEvents.on(window, "scroll", inViewElements, collectOnScrollData);
rafUpdate();
// make sure the offset and heights are correct, every x ms
setInterval(rafUpdate, 5000);
module.exports = {
/**
* register function to add new inview elements
* @method register
* @param elements
* @param threshold on scale from 0 to 1. 0 means it triggers directly, 1 means it must be full visible
* @param [callback]
*/
register: function(elements, threshold, callback) {
jQuery(elements).each(function() {
var el = jQuery(this);
// attribute before the argument
threshold = parseFloat(el.data("inview-threshold")) || threshold;
inview_elements.push({
element: el,
threshold: threshold,
callback: callback
});
});
},
/**
* update all inview elements on the next animation frame
* @method update
*/
update: rafUpdate
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment