site/js/elevator.js

224 lines
5.3 KiB
JavaScript

/*!
* Elevator.js
*
* MIT licensed
* Copyright (C) 2015 Tim Holman, http://tholman.com
*/
/*********************************************
* Elevator.js
*********************************************/
var Elevator = function(options) {
'use strict';
// Elements
var body = null;
// Scroll vars
var animation = null;
var duration = null; // ms
var customDuration = false;
var startTime = null;
var startPosition = null;
var endPosition = 0;
var elevating = false;
var mainAudio;
var endAudio;
var that = this;
/**
* Utils
*/
// Thanks Mr Penner - http://robertpenner.com/easing/
function easeInOutQuad( t, b, c, d ) {
t /= d / 2;
if ( t < 1 ) return c / 2 * t * t + b;
t--;
return -c / 2 * ( t * ( t -2 ) - 1 ) + b;
}
function extendParameters(options, defaults){
for( var option in defaults ){
var t = options[option] === undefined && typeof option !== "function";
if(t){
options[option] = defaults[option];
}
}
return options;
}
function getVerticalOffset(element) {
var verticalOffset = 0;
while( element ){
verticalOffset += element.offsetTop || 0;
element = element.offsetParent;
}
return verticalOffset;
}
/**
* Main
*/
// Time is passed through requestAnimationFrame, what a world!
function animateLoop( time ) {
if ( !startTime ) {
startTime = time;
}
var timeSoFar = time - startTime;
var easedPosition = easeInOutQuad(timeSoFar, startPosition, endPosition - startPosition, duration);
window.scrollTo(0, easedPosition);
if( timeSoFar < duration ) {
animation = requestAnimationFrame(animateLoop);
} else {
animationFinished();
}
}
// ELEVATE!
// /
// ____
// .' '=====<0
// |======|
// |======|
// [IIIIII[\--()
// |_______|
// C O O O D
// C O O O D
// C O O O D
// C__O__O__O__D
// [_____________]
this.elevate = function() {
if( elevating ) {
return;
}
elevating = true;
startPosition = (document.documentElement.scrollTop || body.scrollTop);
// No custom duration set, so we travel at pixels per millisecond. (0.75px per ms)
if( !customDuration ) {
duration = (startPosition * 1.5);
}
requestAnimationFrame( animateLoop );
// Start music!
if( mainAudio ) {
mainAudio.play();
}
};
function browserMeetsRequirements() {
return window.requestAnimationFrame && window.Audio && window.addEventListener;
}
function resetPositions() {
startTime = null;
startPosition = null;
elevating = false;
}
function animationFinished() {
resetPositions();
// Stop music!
if( mainAudio ) {
mainAudio.pause();
mainAudio.currentTime = 0;
}
if( endAudio ) {
endAudio.play();
}
}
function onWindowBlur() {
// If animating, go straight to the top. And play no more music.
if( elevating ) {
cancelAnimationFrame( animation );
resetPositions();
if( mainAudio ) {
mainAudio.pause();
mainAudio.currentTime = 0;
}
window.scrollTo(0, endPosition);
}
}
function bindElevateToElement( element ) {
if( element.addEventListener ) {
element.addEventListener('click', that.elevate, false);
} else {
// Older browsers
element.attachEvent('onclick', function() {
document.documentElement.scrollTop = endPosition;
document.body.scrollTop = endPosition;
window.scroll(0, endPosition);
});
}
}
function init( _options ) {
// Bind to element click event, if need be.
body = document.body;
var defaults = {
duration: undefined,
mainAudio: false,
endAudio: false,
preloadAudio: true,
loopAudio: true,
};
_options = extendParameters(_options, defaults);
if( _options.element ) {
bindElevateToElement( _options.element );
}
// Take the stairs instead
if( !browserMeetsRequirements() ) {
return;
}
if( _options.duration ) {
customDuration = true;
duration = _options.duration;
}
if( _options.targetElement ) {
endPosition = getVerticalOffset(_options.targetElement);
}
window.addEventListener('blur', onWindowBlur, false);
if( _options.mainAudio ) {
mainAudio = new Audio( _options.mainAudio );
mainAudio.setAttribute( 'preload', _options.preloadAudio );
mainAudio.setAttribute( 'loop', _options.loopAudio );
}
if( _options.endAudio ) {
endAudio = new Audio( _options.endAudio );
endAudio.setAttribute( 'preload', 'true' );
}
}
init(options);
};