diff options
author | Bartek Szopka <bartek.szopka+github@gmail.com> | 2012-02-01 21:28:55 +0100 |
---|---|---|
committer | Bartek Szopka <bartek.szopka+github@gmail.com> | 2012-02-15 21:16:43 +0100 |
commit | cfe6448594157e3c5ce2383525ce6f23f0a07bb3 (patch) | |
tree | 97249d6f3820d1ab5ebb3b66c1916a91d0c6722f | |
parent | 9641f5750ba9a8a46c2bf4e5f7cdec192cc39166 (diff) | |
download | impress.js-cfe6448594157e3c5ce2383525ce6f23f0a07bb3.tar.gz |
impressive API
-rw-r--r-- | index.html | 1 | ||||
-rw-r--r-- | js/impress.js | 411 |
2 files changed, 226 insertions, 186 deletions
@@ -286,6 +286,7 @@ --> <script src="js/impress.js"></script> +<script>impress();</script> </body> </html> diff --git a/js/impress.js b/js/impress.js index 34339f5..0e810a6 100644 --- a/js/impress.js +++ b/js/impress.js @@ -86,7 +86,13 @@ var scale = function ( s ) { return " scale(" + s + ") "; - } + }; + + var getElementFromUrl = function () { + // get id from url # by removing `#` or `#/` from the beginning, + // so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work + return byId( window.location.hash.replace(/^#\/?/,"") ); + }; // CHECK SUPPORT @@ -94,223 +100,255 @@ var impressSupported = ( pfx("perspective") != null ) && ( ua.search(/(iphone)|(ipod)|(ipad)|(android)/) == -1 ); - // DOM ELEMENTS - - var impress = byId("impress"); - - if (!impressSupported) { - impress.className = "impress-not-supported"; - return; - } else { - impress.className = ""; - } - - var canvas = document.createElement("div"); - canvas.className = "canvas"; - - arrayify( impress.childNodes ).forEach(function ( el ) { - canvas.appendChild( el ); - }); - impress.appendChild(canvas); - - var steps = $$(".step", impress); - - // SETUP - // set initial values and defaults + var roots = {}; - document.documentElement.style.height = "100%"; - - css(document.body, { - height: "100%", - overflow: "hidden" - }); + var impress = window.impress = function ( rootId ) { - var props = { - position: "absolute", - transformOrigin: "top left", - transition: "all 0s ease-in-out", - transformStyle: "preserve-3d" - } - - css(impress, props); - css(impress, { - top: "50%", - left: "50%", - perspective: "1000px" - }); - css(canvas, props); - - var current = { - translate: { x: 0, y: 0, z: 0 }, - rotate: { x: 0, y: 0, z: 0 }, - scale: 1 - }; - - var stepData = {}; - - steps.forEach(function ( el, idx ) { - var data = el.dataset, - step = { - translate: { - x: data.x || 0, - y: data.y || 0, - z: data.z || 0 - }, - rotate: { - x: data.rotateX || 0, - y: data.rotateY || 0, - z: data.rotateZ || data.rotate || 0 - }, - scale: data.scale || 1, - el: el - }; + rootId = rootId || "impress"; - if ( !el.id ) { - el.id = "step-" + (idx + 1); + // if already initialized just return the API + if (roots["impress-root-" + rootId]) { + return roots["impress-root-" + rootId]; } - stepData["impress-" + el.id] = step; + // DOM ELEMENTS - css(el, { - position: "absolute", - transform: "translate(-50%,-50%)" + - translate(step.translate) + - rotate(step.rotate) + - scale(step.scale), - transformStyle: "preserve-3d" - }); + var root = byId( rootId ); - }); - - // making given step active - - var active = null; - var hashTimeout = null; - - var isStep = function ( el ) { - return !!(el && el.id && stepData["impress-" + el.id]); - } - - var select = function ( el ) { - if ( !el || !isStep(el) || el == active) { - // selected element is not defined as step or is already active - return false; + if (!impressSupported) { + root.className = "impress-not-supported"; + return; + } else { + root.className = ""; } - // Sometimes it's possible to trigger focus on first link with some keyboard action. - // Browser in such a case tries to scroll the page to make this element visible - // (even that body overflow is set to hidden) and it breaks our careful positioning. - // - // So, as a lousy (and lazy) workaround we will make the page scroll back to the top - // whenever slide is selected - // - // If you are reading this and know any better way to handle it, I'll be glad to hear about it! - window.scrollTo(0, 0); + var canvas = document.createElement("div"); + canvas.className = "canvas"; - var step = stepData["impress-" + el.id]; + arrayify( root.childNodes ).forEach(function ( el ) { + canvas.appendChild( el ); + }); + root.appendChild(canvas); - if ( active ) { - active.classList.remove("active"); - } - el.classList.add("active"); + var steps = $$(".step", root); - impress.className = "step-" + el.id; + // SETUP + // set initial values and defaults - // `#/step-id` is used instead of `#step-id` to prevent default browser - // scrolling to element in hash - // - // and it has to be set after animation finishes, because in chrome it - // causes transtion being laggy - window.clearTimeout( hashTimeout ); - hashTimeout = window.setTimeout(function () { - window.location.hash = "#/" + el.id; - }, 1000); + document.documentElement.style.height = "100%"; - var target = { - rotate: { - x: -parseInt(step.rotate.x, 10), - y: -parseInt(step.rotate.y, 10), - z: -parseInt(step.rotate.z, 10) - }, - translate: { - x: -step.translate.x, - y: -step.translate.y, - z: -step.translate.z - }, - scale: 1 / parseFloat(step.scale) - }; + css(document.body, { + height: "100%", + overflow: "hidden" + }); + + var props = { + position: "absolute", + transformOrigin: "top left", + transition: "all 0s ease-in-out", + transformStyle: "preserve-3d" + } - // check if the transition is zooming in or not - var zoomin = target.scale >= current.scale; + css(root, props); + css(root, { + top: "50%", + left: "50%", + perspective: "1000px" + }); + css(canvas, props); - // if presentation starts (nothing is active yet) - // don't animate (set duration to 0) - var duration = (active) ? "1s" : "0"; + var current = { + translate: { x: 0, y: 0, z: 0 }, + rotate: { x: 0, y: 0, z: 0 }, + scale: 1 + }; + + var stepData = {}; - css(impress, { - // to keep the perspective look similar for different scales - // we need to 'scale' the perspective, too - perspective: step.scale * 1000 + "px", - transform: scale(target.scale), - transitionDuration: duration, - transitionDelay: (zoomin ? "500ms" : "0ms") - }); + var isStep = function ( el ) { + return !!(el && el.id && stepData["impress-" + el.id]); + } - css(canvas, { - transform: rotate(target.rotate, true) + translate(target.translate), - transitionDuration: duration, - transitionDelay: (zoomin ? "0ms" : "500ms") + steps.forEach(function ( el, idx ) { + var data = el.dataset, + step = { + translate: { + x: data.x || 0, + y: data.y || 0, + z: data.z || 0 + }, + rotate: { + x: data.rotateX || 0, + y: data.rotateY || 0, + z: data.rotateZ || data.rotate || 0 + }, + scale: data.scale || 1, + el: el + }; + + if ( !el.id ) { + el.id = "step-" + (idx + 1); + } + + stepData["impress-" + el.id] = step; + + css(el, { + position: "absolute", + transform: "translate(-50%,-50%)" + + translate(step.translate) + + rotate(step.rotate) + + scale(step.scale), + transformStyle: "preserve-3d" + }); + }); + + // making given step active + + var active = null; + var hashTimeout = null; - current = target; - active = el; + var goto = function ( el ) { + if ( !isStep(el) || el == active) { + // selected element is not defined as step or is already active + return false; + } + + // Sometimes it's possible to trigger focus on first link with some keyboard action. + // Browser in such a case tries to scroll the page to make this element visible + // (even that body overflow is set to hidden) and it breaks our careful positioning. + // + // So, as a lousy (and lazy) workaround we will make the page scroll back to the top + // whenever slide is selected + // + // If you are reading this and know any better way to handle it, I'll be glad to hear about it! + window.scrollTo(0, 0); + + var step = stepData["impress-" + el.id]; + + if ( active ) { + active.classList.remove("active"); + } + el.classList.add("active"); + + root.className = "step-" + el.id; + + // `#/step-id` is used instead of `#step-id` to prevent default browser + // scrolling to element in hash + // + // and it has to be set after animation finishes, because in chrome it + // causes transtion being laggy + window.clearTimeout( hashTimeout ); + hashTimeout = window.setTimeout(function () { + window.location.hash = "#/" + el.id; + }, 1000); + + var target = { + rotate: { + x: -parseInt(step.rotate.x, 10), + y: -parseInt(step.rotate.y, 10), + z: -parseInt(step.rotate.z, 10) + }, + translate: { + x: -step.translate.x, + y: -step.translate.y, + z: -step.translate.z + }, + scale: 1 / parseFloat(step.scale) + }; + + // check if the transition is zooming in or not + var zoomin = target.scale >= current.scale; + + // if presentation starts (nothing is active yet) + // don't animate (set duration to 0) + var duration = (active) ? "1s" : "0"; + + css(root, { + // to keep the perspective look similar for different scales + // we need to 'scale' the perspective, too + perspective: step.scale * 1000 + "px", + transform: scale(target.scale), + transitionDuration: duration, + transitionDelay: (zoomin ? "500ms" : "0ms") + }); + + css(canvas, { + transform: rotate(target.rotate, true) + translate(target.translate), + transitionDuration: duration, + transitionDelay: (zoomin ? "0ms" : "500ms") + }); + + current = target; + active = el; + + return el; + }; - return el; - }; - - var selectPrev = function () { - var prev = steps.indexOf( active ) - 1; - prev = prev >= 0 ? steps[ prev ] : steps[ steps.length-1 ]; + var prev = function () { + var prev = steps.indexOf( active ) - 1; + prev = prev >= 0 ? steps[ prev ] : steps[ steps.length-1 ]; + + return goto(prev); + }; - return select(prev); - }; - - var selectNext = function () { - var next = steps.indexOf( active ) + 1; - next = next < steps.length ? steps[ next ] : steps[ 0 ]; + var next = function () { + var next = steps.indexOf( active ) + 1; + next = next < steps.length ? steps[ next ] : steps[ 0 ]; + + return goto(next); + }; - return select(next); - }; - - // EVENTS + window.addEventListener("hashchange", function () { + goto( getElementFromUrl() ); + }, false); + + // START + // by selecting step defined in url or first step of the presentation + goto(getElementFromUrl() || steps[0]); + + return (roots[ "impress-root-" + rootId ] = { + goto: goto, + next: next, + prev: prev + }); + + } +})(document, window); + +// EVENTS + +(function ( document, window ) { + 'use strict'; + // keyboard navigation handler document.addEventListener("keydown", function ( event ) { if ( event.keyCode == 9 || ( event.keyCode >= 32 && event.keyCode <= 34 ) || (event.keyCode >= 37 && event.keyCode <= 40) ) { switch( event.keyCode ) { case 33: ; // pg up case 37: ; // left case 38: // up - selectPrev(); + impress().prev(); break; case 9: ; // tab case 32: ; // space case 34: ; // pg down case 39: ; // right case 40: // down - selectNext(); + impress().next(); break; } event.preventDefault(); } }, false); - + + // delegated handler for clicking on the links to presentation steps document.addEventListener("click", function ( event ) { // event delegation with "bubbling" - // check if event target (or any of its parents is a link or a step) + // check if event target (or any of its parents is a link) var target = event.target; while ( (target.tagName != "A") && - (!isStep(target)) && (target != document.body) ) { target = target.parentNode; } @@ -320,28 +358,29 @@ // if it's a link to presentation step, target this step if ( href && href[0] == '#' ) { - target = byId( href.slice(1) ); + target = document.getElementById( href.slice(1) ); } } - if ( select(target) ) { + if ( impress().goto(target) ) { + event.stopImmediatePropagation(); event.preventDefault(); } }, false); - var getElementFromUrl = function () { - // get id from url # by removing `#` or `#/` from the beginning, - // so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work - return byId( window.location.hash.replace(/^#\/?/,"") ); - } - - window.addEventListener("hashchange", function () { - select( getElementFromUrl() ); + // delegated handler for clicking on step elements + document.addEventListener("click", function ( event ) { + var target = event.target; + // find closest step element + while ( !target.classList.contains("step") && + (target != document.body) ) { + target = target.parentNode; + } + + if ( impress().goto(target) ) { + event.preventDefault(); + } }, false); - // START - // by selecting step defined in url or first step of the presentation - select(getElementFromUrl() || steps[0]); - })(document, window); |