diff options
Diffstat (limited to 'js/reveal.js')
-rw-r--r-- | js/reveal.js | 202 |
1 files changed, 124 insertions, 78 deletions
diff --git a/js/reveal.js b/js/reveal.js index a4881e0..33b58cf 100644 --- a/js/reveal.js +++ b/js/reveal.js @@ -25,8 +25,7 @@ var Reveal = (function(){ mouseWheel: true, rollingLinks: true, transition: 'default', - theme: 'default', - swipeDist: 40 + theme: 'default' }, // Slides may hold a data-state attribute which we pick up and apply @@ -54,8 +53,17 @@ var Reveal = (function(){ mouseWheelTimeout = 0, // Delays updates to the URL due to a Chrome thumbnailer bug - writeURLTimeout = 0; - + writeURLTimeout = 0, + + // Holds information about the currently ongoing touch input + touch = { + startX: 0, + startY: 0, + startSpan: 0, + startCount: 0, + handled: false, + threshold: 40 + }; /** @@ -82,7 +90,7 @@ var Reveal = (function(){ dom.controlsUp = document.querySelector( '#reveal .controls .up' ); dom.controlsDown = document.querySelector( '#reveal .controls .down' ); - addEvents(); + addEventListeners(); // Copy options over to our config object extend( config, options ); @@ -133,8 +141,8 @@ var Reveal = (function(){ } } - function addEvents() { - // Bind all view events + + function addEventListeners() { document.addEventListener( 'keydown', onDocumentKeyDown, false ); document.addEventListener( 'touchstart', onDocumentTouchStart, false ); document.addEventListener( 'touchmove', onDocumentTouchMove, false ); @@ -146,8 +154,8 @@ var Reveal = (function(){ dom.controlsUp.addEventListener( 'click', preventAndForward( navigateUp ), false ); dom.controlsDown.addEventListener( 'click', preventAndForward( navigateDown ), false ); } - function removeEvents(){ - // Bind all view events + + function removeEventListeners() { document.removeEventListener( 'keydown', onDocumentKeyDown, false ); document.removeEventListener( 'touchstart', onDocumentTouchStart, false ); document.removeEventListener( 'touchmove', onDocumentTouchMove, false ); @@ -159,6 +167,7 @@ var Reveal = (function(){ dom.controlsUp.removeEventListener( 'click', preventAndForward( navigateUp ), false ); dom.controlsDown.removeEventListener( 'click', preventAndForward( navigateDown ), false ); } + /** * Extend object a with the properties of object b. * If there's a conflict, object b takes precedence. @@ -169,6 +178,13 @@ var Reveal = (function(){ } } + function distanceBetween( a, b ) { + var dx = a.x - b.x, + dy = a.y - b.y; + + return Math.sqrt( dx*dx + dy*dy ); + } + /** * Prevents an events defaults behavior calls the * specified delegate. @@ -246,81 +262,97 @@ var Reveal = (function(){ } } + /** - * Handler for the document level 'touchstart' event. - * - * This enables very basic tap interaction for touch - * devices. Added mainly for performance testing of 3D - * transforms on iOS but was so happily surprised with - * how smoothly it runs so I left it in here. Apple +1 - * - * @param {Object} event + * Handler for the document level 'touchstart' event, + * enables support for swipe and pinch gestures. */ - var touchStart = {} - var gesture = false; function onDocumentTouchStart( event ) { - - touchStart = { - x: event.touches[0].clientX, - y: event.touches[0].clientY - }; - if( event.target.tagName.toLowerCase() === 'a' || event.target.tagName.toLowerCase() === 'img' ) { - } else { - event.preventDefault(); - } + touch.startX = event.touches[0].clientX; + touch.startY = event.touches[0].clientY; + touch.startCount = event.touches.length; + + // If there's two touches we need to memorize the distance + // between those two points to detect pinching + if( event.touches.length === 2 ) { + touch.startSpan = distanceBetween( { + x: event.touches[1].clientX, + y: event.touches[1].clientY + }, { + x: touch.startX, + y: touch.startY + } ); + } } + /** + * Handler for the document level 'touchmove' event. + */ function onDocumentTouchMove( event ) { - - event.preventDefault(); - - if(!gesture) { - var touch = { - x: event.touches[0].clientX, - y: event.touches[0].clientY - }; - if((touch.x - touchStart.x) > config.swipeDist){ - gesture = true; - navigateLeft(); - } else if((touch.x - touchStart.x) < -config.swipeDist){ - gesture = true; - navigateRight(); - } else if((touch.y - touchStart.y) > config.swipeDist){ - gesture = true; - navigateUp(); - } else if((touch.y - touchStart.y) < -config.swipeDist){ - gesture = true; - navigateDown(); + // Each touch should only trigger one action + if( !touch.handled ) { + var currentX = event.touches[0].clientX; + var currentY = event.touches[0].clientY; + + // If the touch started off with two points and still has + // two active touches; test for the pinch gesture + if( event.touches.length === 2 && touch.startCount === 2 ) { + + // The current distance in pixels between the two touch points + var currentSpan = distanceBetween( { + x: event.touches[1].clientX, + y: event.touches[1].clientY + }, { + x: touch.startX, + y: touch.startY + } ); + + // If the span is larger than the desire amount we've got + // ourselves a pinch + if( Math.abs( touch.startSpan - currentSpan ) > touch.threshold ) { + touch.handled = true; + + if( currentSpan < touch.startSpan ) { + activateOverview(); + } + else { + deactivateOverview(); + } + } + } + // There was only one touch point, look for a swipe + else if( event.touches.length === 1 ) { + var deltaX = currentX - touch.startX, + deltaY = currentY - touch.startY; + + if( deltaX > touch.threshold && Math.abs( deltaX ) > Math.abs( deltaY ) ) { + touch.handled = true; + navigateLeft(); + } + else if( deltaX < -touch.threshold && Math.abs( deltaX ) > Math.abs( deltaY ) ) { + touch.handled = true; + navigateRight(); + } + else if( deltaY > touch.threshold ) { + touch.handled = true; + navigateUp(); + } + else if( deltaY < -touch.threshold ) { + touch.handled = true; + navigateDown(); + } + } + + event.preventDefault(); } } + + /** + * Handler for the document level 'touchend' event. + */ function onDocumentTouchEnd( event ) { - if(!gesture){ - // Never prevent taps on anchors and images - if( event.target.tagName.toLowerCase() === 'a' || event.target.tagName.toLowerCase() === 'img' ) { - return; - } - - // Define the extent of the areas that may be tapped - // to navigate - var wt = window.innerWidth * 0.3; - var ht = window.innerHeight * 0.3; - - if( touchStart.x < wt ) { - navigateLeft(); - } - else if( touchStart.x > window.innerWidth - wt ) { - navigateRight(); - } - else if( touchStart.y < ht ) { - navigateUp(); - } - else if( touchStart.y > window.innerHeight - ht ) { - navigateDown(); - } - } - gesture = false; - event.preventDefault(); + touch.handled = false; } /** @@ -706,6 +738,9 @@ var Reveal = (function(){ var verticalFragments = document.querySelectorAll( VERTICAL_SLIDES_SELECTOR + '.present .fragment:not(.visible)' ); if( verticalFragments.length ) { verticalFragments[0].classList.add( 'visible' ); + + // Notify subscribers of the change + dispatchEvent( 'fragmentshown', { fragment: verticalFragments[0] } ); return true; } } @@ -714,6 +749,9 @@ var Reveal = (function(){ var horizontalFragments = document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR + '.present .fragment:not(.visible)' ); if( horizontalFragments.length ) { horizontalFragments[0].classList.add( 'visible' ); + + // Notify subscribers of the change + dispatchEvent( 'fragmentshown', { fragment: horizontalFragments[0] } ); return true; } } @@ -733,6 +771,9 @@ var Reveal = (function(){ var verticalFragments = document.querySelectorAll( VERTICAL_SLIDES_SELECTOR + '.present .fragment.visible' ); if( verticalFragments.length ) { verticalFragments[ verticalFragments.length - 1 ].classList.remove( 'visible' ); + + // Notify subscribers of the change + dispatchEvent( 'fragmenthidden', { fragment: verticalFragments[0] } ); return true; } } @@ -741,6 +782,9 @@ var Reveal = (function(){ var horizontalFragments = document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR + '.present .fragment.visible' ); if( horizontalFragments.length ) { horizontalFragments[ horizontalFragments.length - 1 ].classList.remove( 'visible' ); + + // Notify subscribers of the change + dispatchEvent( 'fragmenthidden', { fragment: horizontalFragments[0] } ); return true; } } @@ -826,7 +870,11 @@ var Reveal = (function(){ availableRoutes().down ? navigateDown() : navigateRight(); } } - function overviewToggle (){ + + /** + * Toggles the slide overview mode on and off. + */ + function toggleOverview() { if( overviewIsActive() ) { deactivateOverview(); } @@ -843,9 +891,7 @@ var Reveal = (function(){ navigateRight: navigateRight, navigateUp: navigateUp, navigateDown: navigateDown, - overviewToggle: overviewToggle, - addEvents: addEvents, - removeEvents: removeEvents, + toggleOverview: toggleOverview, // Forward event binding to the reveal DOM element addEventListener: function( type, listener, useCapture ) { |