/*! * 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 mainAudioPath; var endAudioPath; var preloadAudio; var loopAudio; 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; } function getScrollTop() { return window.pageYOffset || document.documentElement.scrollTop || body.scrollTop || 0; } function playAudio(audio) { var playPromise = audio.play(); if (playPromise && playPromise.catch) { playPromise.catch(() => 0); } } /** * 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 = getScrollTop(); // No custom duration set, so we travel at pixels per millisecond. (0.75px per ms) if (!customDuration) { duration = (startPosition * 1.5); } requestAnimationFrame(animateLoop); loadAudio(); // Start music! if (mainAudio) { playAudio(mainAudio); } }; 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) { playAudio(endAudio); } } 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 handleElevate(event) { if (event && event.type === 'touchend') event.preventDefault(); that.elevate(); } function bindElevateToElement(element) { if (element.addEventListener) { element.addEventListener('click', handleElevate, false); element.addEventListener('touchend', handleElevate, false); } else { // Older browsers element.attachEvent('onclick', function () { document.documentElement.scrollTop = endPosition; document.body.scrollTop = endPosition; window.scroll(0, endPosition); }); } } function loadAudio() { if (!mainAudio && mainAudioPath) { mainAudio = new Audio(mainAudioPath); mainAudio.setAttribute('preload', preloadAudio); mainAudio.setAttribute('loop', loopAudio); } if (!endAudio && endAudioPath) { endAudio = new Audio(endAudioPath); endAudio.setAttribute('preload', 'auto'); } } function init(_options) { // Bind to element click event, if need be. body = document.body; var defaults = { duration: undefined, mainAudio: false, endAudio: false, preloadAudio: 'none', loopAudio: true, }; _options = extendParameters(_options, defaults); if (_options.elements) { for (var i = 0; i < _options.elements.length; i++) { bindElevateToElement(_options.elements[i]); } } else 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); mainAudioPath = _options.mainAudio; endAudioPath = _options.endAudio; preloadAudio = _options.preloadAudio; loopAudio = _options.loopAudio; } init(options); };