Skip to content

Instantly share code, notes, and snippets.

@elzii
Created August 30, 2016 18:58
Show Gist options
  • Save elzii/0dd0c1d100bb4770367d52e50b8b9e96 to your computer and use it in GitHub Desktop.
Save elzii/0dd0c1d100bb4770367d52e50b8b9e96 to your computer and use it in GitHub Desktop.
/*
* @author Mudit Ameta
* @license https://github.com/zeusdeux/isInViewport/blob/master/license.md MIT
*/
!function(a,b){function c(b){var c,d=a("<div></div>").css({width:"100%"});return b.append(d),c=b.width()-d.width(),d.remove(),c}function d(e,f){var g=e.getBoundingClientRect(),h=g.top,i=g.bottom,j=g.left,k=g.right,l=a.extend({tolerance:0,viewport:b},f),m=!1,n=l.viewport.jquery?l.viewport:a(l.viewport);n.length||(console.warn("isInViewport: The viewport selector you have provided matches no element on page."),console.warn("isInViewport: Defaulting to viewport as window"),n=a(b));var o=n.height(),p=n.width(),q=n[0].toString();if(n[0]!==b&&"[object Window]"!==q&&"[object DOMWindow]"!==q){var r=n[0].getBoundingClientRect();h-=r.top,i-=r.top,j-=r.left,k-=r.left,d.scrollBarWidth=d.scrollBarWidth||c(n),p-=d.scrollBarWidth}return l.tolerance=~~Math.round(parseFloat(l.tolerance)),l.tolerance<0&&(l.tolerance=o+l.tolerance),0>=k||j>=p?m:m=l.tolerance?h<=l.tolerance&&i>=l.tolerance:i>0&&o>=h}String.prototype.hasOwnProperty("trim")||(String.prototype.trim=function(){return this.replace(/^\s*(.*?)\s*$/,"$1")});var e=function(b){if(1===arguments.length&&"function"==typeof b&&(b=[b]),!(b instanceof Array))throw new SyntaxError("isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions");for(var c=0;c<b.length;c++)if("function"==typeof b[c])for(var d=0;d<this.length;d++)b[c].call(a(this[d]));else console.warn("isInViewport: Argument(s) passed to .do/.run should be a function or an array of functions"),console.warn("isInViewport: Ignoring non-function values in array and moving on");return this};a.fn["do"]=function(a){return console.warn("isInViewport: .do is deprecated as it causes issues in IE and some browsers since it's a reserved word. Use $.fn.run instead i.e., $(el).run(fn)."),e(a)},a.fn.run=e;var f=function(b){if(b){var c=b.split(",");return 1===c.length&&isNaN(c[0])&&(c[1]=c[0],c[0]=void 0),{tolerance:c[0]?c[0].trim():void 0,viewport:c[1]?a(c[1].trim()):void 0}}return{}};a.extend(a.expr[":"],{"in-viewport":a.expr.createPseudo?a.expr.createPseudo(function(a){return function(b){return d(b,f(a))}}):function(a,b,c){return d(a,f(c[3]))}}),a.fn.isInViewport=function(a){return this.filter(function(b,c){return d(c,a)})}}(jQuery,window);
$(document).ready(function() {
var $win = $(window);
var cardParallaxDegrees = 10;
var notchTextTemplate = '<div style="padding: 2px 13px;">0%</div>';
var timelineInterval;
var windowWidth = $win.width();
var windowHeight = $win.height();
var $sectionTwo = $('.section-two');
var $sectionThree = $('.section-three');
var $imageGridWrapper = $('.imggridwrap');
var $timelineNotch = $('.timeline-carrot');
var $timelineNumber = $('.timeline-carrot-number');
var $actionGroups = $('.item-group');
var parallaxScales = {
card1: 100,
card2: 60,
card3: 60,
card4: 60,
card5: 60,
card6: 60,
card7: 30,
card8: 30,
card9: 30,
card10: 30,
};
// notches
var $notchScroll = $('.bounding-box-scroll-x');
var $notchScrollCarrot = $notchScroll.children('.action-list-carrot');
var $notchScrollText = $(notchTextTemplate).appendTo($notchScroll);
var $notchScrollContent = $notchScrollText.add($notchScrollCarrot);
var $notchMouseX = $('.bounding-box-mouse-x');
var $notchMouseXText = $(notchTextTemplate).appendTo($notchMouseX);
var $notchMouseXCarrot = $notchMouseX.children('.action-list-carrot');
var $notchMouseXContent = $notchMouseXText.add($notchMouseXCarrot);
var $notchMouseY = $('.bounding-box-mouse-y');
var $notchMouseYCarrot = $notchMouseY.children('.action-list-carrot');
var $notchMouseYText = $(notchTextTemplate).appendTo($notchMouseY);
var $notchMouseYContent = $notchMouseYText.add($notchMouseYCarrot);
var allNotches = $notchScrollContent
.add($notchMouseXContent)
.add($notchMouseYContent);
allNotches.css({
position: 'absolute',
width: 44,
height: 24,
color: '#272727',
fontSize: 11,
textAlign: 'right'
});
// scroll parallax
var sectionTwoTop = $sectionTwo.offset().top;
var sectionTwoHeight = $sectionTwo.height();
var cards = {};
for (var i = 1; i <= 10; i++) {
var $card = $(i === 1 ? '.parallax-card.scroll' : ('.card-' + i));
cards[i] = $card;
// Perf improvements
$card.css('will-change', 'transform');
}
// mouse parallax
var parallaxCardMouse = $('.parallax-card.mouse');
var cardMouseTop = $('.card-mouse-top');
var weeBitsA = $('.wee-bits-a');
var weeBitsB = $('.wee-bits-b');
// events
var clientX = $win.width() / 2;
var clientY = $win.height() / 2;
function onMouseMove(e) {
if (!$sectionThree.is(':in-viewport')) { return; }
if (typeof e.clientX === 'number') {
clientX = e.clientX;
}
if (typeof e.clientY === 'number') {
clientY = e.clientY;
}
updateMouseElements();
}
function onTouchMove(e) {
var event = e.originalEvent;
var touch = event && event.targetTouches && event.targetTouches[0];
if (touch) {
clientX = touch.clientX;
updateMouseElementsIfVisible();
}
}
function onScroll(e) {
updateParallaxCardsIfVisible();
updateMouseElementsIfVisible();
}
function onResize(e) {
windowWidth = $win.width();
windowHeight = $win.height();
updateParallaxCardsIfVisible();
updateMouseElementsIfVisible();
}
function updateMouseElementsIfVisible() {
if ($sectionThree.is(':in-viewport')) {
updateMouseElements();
}
}
function updateMouseElements() {
var scrollTop = $win.scrollTop();
var scrollLeft = $win.scrollLeft();
// notches
var parallaxCardMouseCenterLeft = (parallaxCardMouse.offset().left + (parallaxCardMouse.width() / 2)) - scrollLeft;
var parallaxCardMouseCenterTop = (parallaxCardMouse.offset().top + (parallaxCardMouse.height() / 2)) - scrollTop;
var mouseXRatio = (clientX - parallaxCardMouseCenterLeft) /
((clientX < parallaxCardMouseCenterLeft) ? (parallaxCardMouseCenterLeft) : (windowWidth - parallaxCardMouseCenterLeft));
var mouseX = Math.floor(((mouseXRatio + 1) / 2) * 100) + '%';
var mouseYRatio = (clientY - parallaxCardMouseCenterTop) /
((clientY < parallaxCardMouseCenterTop) ? (parallaxCardMouseCenterTop) : (windowHeight - parallaxCardMouseCenterTop));
var mouseY = Math.floor(((mouseYRatio + 1) / 2) * 100) + '%';
requestAnimationFrame(function() {
$notchMouseXContent.css('top', mouseX);
$notchMouseXText.text(mouseX);
$notchMouseYContent.css('top', mouseY);
$notchMouseYText.text(mouseY);
// cards parallax
parallaxCardMouse.parent().css('perspective', '2000px');
parallaxCardMouse
.css('transform', 'translate3d(0, 0, 0) rotateX(' + (-mouseYRatio * cardParallaxDegrees) + 'deg) rotateY(' + (mouseXRatio * cardParallaxDegrees) + 'deg)')
.css('perspective', '2000px');
cardMouseTop.css('transform', 'translate3d(0, 0, 0) rotateX(' + (-mouseYRatio * cardParallaxDegrees) + 'deg) rotateY(' + (mouseXRatio * cardParallaxDegrees) + 'deg) translateZ(100px)')
weeBitsA.css({
marginLeft: mouseXRatio * 15,
marginTop: mouseYRatio * 15
});
weeBitsB.css({
marginLeft: mouseXRatio * 35,
marginTop: mouseYRatio * 35
});
});
}
function translateCard(card, yPercent) {
card.css('transform', 'translate3d(0,' + yPercent + '%,0)');
}
function updateParallaxCardsIfVisible() {
if ($sectionTwo.is(':in-viewport')) {
updateParallaxCards();
}
}
function updateParallaxCards() {
requestAnimationFrame(function() {
var scrollTop = window.pageYOffset || $win.scrollTop();
var scrollRatio = Math.max(Math.min(
scrollTop / (((sectionTwoTop + (sectionTwoHeight / 2)) - (windowHeight / 2)) * 2)
, 1), 0);
var scrollOffsetRatio = -scrollRatio + 0.5;
var scrollX = Math.floor(scrollRatio * 100) + '%';
// notches
$notchScrollContent.css('top', scrollX);
$notchScrollText.text(scrollX);
// scroll parallax
for (var i = 1; i <= 10; i++) {
translateCard(cards[i], scrollOffsetRatio * parallaxScales['card' + i]);
}
});
}
function addViewportScrollHandler(options) {
options = options || {};
var $el = options.$el;
var $win = $(window);
var state = options.state;
var offsetTop = options.offsetTop;
var offsetBot = options.offsetBot;
var intro = options.intro;
var outro = options.outro;
Webflow.scroll.on(function() {
var viewTop = $win.scrollTop();
var viewHeight = $win.height();
var top = $el.offset().top;
var height = $el.outerHeight();
if (offsetTop < 1 && offsetTop > 0) offsetTop *= viewHeight;
if (offsetBot < 1 && offsetBot > 0) offsetBot *= viewHeight;
var active = (top + height - offsetTop >= viewTop && top + offsetBot <= viewTop + viewHeight);
if (active === state.active) return;
state.active = active;
active ? intro() : outro();
});
}
function setNotchTime(time, activeGroup, step) {
$timelineNumber.text(time);
$('.active-group').removeClass('active-group');
activeGroup && $('#action-group-' + activeGroup).addClass('active-group');
step && step.next();
}
function rewindPlayhead(step) {
var timelineTime = 7.00;
var parentOffset = $timelineNotch.parent().get(0).getBoundingClientRect();
timelineInterval = window.setInterval(function() {
requestAnimationFrame(function() {
var topOffset = $timelineNotch.get(0).getBoundingClientRect().top;
var timelineTime = (topOffset - parentOffset.top) / 288 * 7.0;
if (timelineTime < 0.2) {
timelineTime = 0.0;
}
setNotchTime(timelineTime.toFixed(2));
});
}, 5);
step && step.next();
}
var boxAnimationReset = false;
var firstPlay = true;
// Trigger box UI animation when the IX interaction starts
addViewportScrollHandler({
$el: $imageGridWrapper,
state: {active: false},
offsetTop: 0.4,
offsetBot: 0.4,
intro: function() {
window.clearInterval(timelineInterval);
if (!(firstPlay || boxAnimationReset)) {
return;
}
tram($timelineNotch)
.set({ y: 0 })
.add('transform 500ms ease-out-quint')
.wait(800)
.then(function() { setNotchTime('1.50', 2, this); })
.then({ y: 55 }) // Open Details
.wait(1300)
.then(function() { setNotchTime('3.20', 3, this); })
.then({ y: 113 }) // Reveal
.wait(600)
.then(function() { setNotchTime('4.30', 4, this); })
.then({ y: 168 }) // Like
.wait(600)
.then(function() { setNotchTime('5.50', 5, this); })
.then({ y: 201 }) // Hide Details
.wait(600)
.then(function() { setNotchTime('6.00', 6, this); })
.then({ y: 233 }) // Close
.wait(600)
.then(function() { setNotchTime('7.00', 0, this); })
.then({ y: 288 })
.wait(400)
.then('transform 1500ms ease-in-out-quad')
.then(function() { rewindPlayhead(this); })
.then({ y: 0 })
.then(function() {
setNotchTime('0.00', 1, this);
window.clearInterval(timelineInterval);
});
firstPlay = false;
},
outro: function() {
boxAnimationReset = false;
},
});
// Reset box animation when it's completely out of view
addViewportScrollHandler({
$el: $imageGridWrapper,
state: {active: false},
offsetTop: 0.0,
offsetBot: 0.0,
intro: function() {},
outro: function() {
$imageGridWrapper.find('*').each(function(index, el) {
var $el = $(el);
tram($el).stop().props = {};
$el.removeAttr('style');
});
window.clearInterval(timelineInterval);
setNotchTime('0.00', 1);
tram($timelineNotch).set({ y: 0 });
boxAnimationReset = true;
},
});
// Initial parallax + mouse element update to avoid a jump
updateParallaxCards();
updateMouseElements();
$(document)
.on('mousemove', onMouseMove)
.on('touchmove', onTouchMove)
.on('scroll', onScroll);
$win.on('resize', onResize);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment