diff options
author | Hakim El Hattab <hakim.elhattab@gmail.com> | 2015-01-29 14:53:06 +0100 |
---|---|---|
committer | Hakim El Hattab <hakim.elhattab@gmail.com> | 2015-01-29 14:53:06 +0100 |
commit | 03400478bd004eb9ef1fe0db96eac13f336e4ab2 (patch) | |
tree | c7815bfac5ee8264fa3d2f12066453e9e6c885ed /js | |
parent | 3b45b618b8f2f3c757a4c4645a381791ece71da8 (diff) | |
parent | 8e66876c4e5881d3a85516e0070094bc8b0d8b9f (diff) | |
download | fosdem-2018-presentation-03400478bd004eb9ef1fe0db96eac13f336e4ab2.tar fosdem-2018-presentation-03400478bd004eb9ef1fe0db96eac13f336e4ab2.tar.gz |
Merge pull request #1119 from hakimel/feature/new-overview
Refactored overview mode
Diffstat (limited to 'js')
-rw-r--r-- | js/reveal.js | 207 |
1 files changed, 135 insertions, 72 deletions
diff --git a/js/reveal.js b/js/reveal.js index 9634c6b..ad2d5a3 100644 --- a/js/reveal.js +++ b/js/reveal.js @@ -147,6 +147,9 @@ // Flags if reveal.js is loaded (has dispatched the 'ready' event) loaded = false, + // Flags if the overview mode is currently active + overview = false, + // The horizontal and vertical index of the currently active slide indexh, indexv, @@ -165,8 +168,9 @@ // The current scale of the presentation (see width/height config) scale = 1, - // The current z position of the presentation container - z = 0, + // CSS transform that is currently applied to the slides container, + // split into two groups + slidesTransform = { layout: '', overview: '' }, // Cached references to DOM elements dom = {}, @@ -296,7 +300,11 @@ features.touch = !!( 'ontouchstart' in window ); - isMobileDevice = navigator.userAgent.match( /(iphone|ipod|ipad|android)/gi ); + // Transitions in the overview are disabled in desktop and + // mobile Safari due to lag + features.overviewTransitions = !/Version\/[\d\.]+.*Safari/.test( navigator.userAgent ); + + isMobileDevice = /(iphone|ipod|ipad|android)/gi.test( navigator.userAgent ); } @@ -1059,6 +1067,27 @@ } /** + * Applies CSS transforms to the slides container. The container + * is transformed from two separate sources: layout and the overview + * mode. + */ + function transformSlides( transforms ) { + + // Pick up new transforms from arguments + if( typeof transforms.layout === 'string' ) slidesTransform.layout = transforms.layout; + if( typeof transforms.overview === 'string' ) slidesTransform.overview = transforms.overview; + + // Apply the transforms to the slides container + if( slidesTransform.layout ) { + transformElement( dom.slides, slidesTransform.layout + ' ' + slidesTransform.overview ); + } + else { + transformElement( dom.slides, slidesTransform.overview ); + } + + } + + /** * Injects the given CSS styles into the DOM. */ function injectStyleSheet( value ) { @@ -1446,7 +1475,6 @@ var size = getComputedSlideSize(); var slidePadding = 20; // TODO Dig this out of DOM - var zTransform = z !== 0 ? 'translateZ(-'+ z +'px)' : ''; // Layout the contents of the slides layoutSlideContents( config.width, config.height, slidePadding ); @@ -1468,13 +1496,13 @@ dom.slides.style.top = ''; dom.slides.style.bottom = ''; dom.slides.style.right = ''; - transformElement( dom.slides, zTransform ); + transformSlides( { layout: '' } ); } else { // Prefer zooming in desktop Chrome so that content remains crisp if( !isMobileDevice && /chrome/i.test( navigator.userAgent ) && typeof dom.slides.style.zoom !== 'undefined' ) { dom.slides.style.zoom = scale; - transformElement( dom.slides, zTransform ); + transformSlides( { layout: '' } ); } // Apply scale transform as a fallback else { @@ -1482,7 +1510,7 @@ dom.slides.style.top = '50%'; dom.slides.style.bottom = 'auto'; dom.slides.style.right = 'auto'; - transformElement( dom.slides, 'translate(-50%, -50%) scale('+ scale +') ' + zTransform ); + transformSlides( { layout: 'translate(-50%, -50%) scale('+ scale +')' } ); } } @@ -1624,98 +1652,122 @@ } /** - * Displays the overview of slides (quick nav) by - * scaling down and arranging all slide elements. - * - * Experimental feature, might be dropped if perf - * can't be improved. + * Displays the overview of slides (quick nav) by scaling + * down and arranging all slide elements. */ function activateOverview() { // Only proceed if enabled in config - if( config.overview ) { - - // Don't auto-slide while in overview mode - cancelAutoSlide(); - - var wasActive = dom.wrapper.classList.contains( 'overview' ); + if( config.overview && !isOverview() ) { - // Set the depth of the presentation. This determinse how far we - // zoom out and varies based on display size. It gets applied at - // the layout step. - z = window.innerWidth < 400 ? 1000 : 2500; + overview = true; dom.wrapper.classList.add( 'overview' ); dom.wrapper.classList.remove( 'overview-deactivating' ); + if( features.overviewTransitions ) { + setTimeout( function() { + dom.wrapper.classList.add( 'overview-animated' ); + }, 1 ); + } + + // Don't auto-slide while in overview mode + cancelAutoSlide(); + // Move the backgrounds element into the slide container to // that the same scaling is applied dom.slides.appendChild( dom.background ); - var horizontalSlides = dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ), - horizontalBackgrounds = dom.background.childNodes; + // Clicking on an overview slide navigates to it + toArray( dom.wrapper.querySelectorAll( SLIDES_SELECTOR ) ).forEach( function( slide ) { + if( !slide.classList.contains( 'stack' ) ) { + slide.addEventListener( 'click', onOverviewSlideClicked, true ); + } + } ); - for( var i = 0, len1 = horizontalSlides.length; i < len1; i++ ) { - var hslide = horizontalSlides[i], - hbackground = horizontalBackgrounds[i], - hoffset = config.rtl ? -105 : 105; + updateSlidesVisibility(); + layoutOverview(); + updateOverview(); - var htransform = 'translate(' + ( ( i - indexh ) * hoffset ) + '%, 0%)'; + layout(); - hslide.setAttribute( 'data-index-h', i ); + // Notify observers of the overview showing + dispatchEvent( 'overviewshown', { + 'indexh': indexh, + 'indexv': indexv, + 'currentSlide': currentSlide + } ); - // Apply CSS transform - transformElement( hslide, htransform ); - transformElement( hbackground, htransform ); + } - if( hslide.classList.contains( 'stack' ) ) { + } - var verticalSlides = hslide.querySelectorAll( 'section' ), - verticalBackgrounds = hbackground.querySelectorAll( '.slide-background' ); + /** + * Uses CSS transforms to position all slides in a grid for + * display inside of the overview mode. + */ + function layoutOverview() { - for( var j = 0, len2 = verticalSlides.length; j < len2; j++ ) { - var verticalIndex = i === indexh ? indexv : getPreviousVerticalIndex( hslide ); + var margin = 70; + var slideWidth = config.width + margin, + slideHeight = config.height + margin; - var vslide = verticalSlides[j], - vbackground = verticalBackgrounds[j]; + // Reverse in RTL mode + if( config.rtl ) { + slideWidth = -slideWidth; + } - var vtransform = 'translate(0%, ' + ( ( j - verticalIndex ) * 105 ) + '%)'; + // Layout slides + toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) ).forEach( function( hslide, h ) { + hslide.setAttribute( 'data-index-h', h ); + transformElement( hslide, 'translate3d(' + ( h * slideWidth ) + 'px, 0, 0)' ); - vslide.setAttribute( 'data-index-h', i ); - vslide.setAttribute( 'data-index-v', j ); + if( hslide.classList.contains( 'stack' ) ) { - // Apply CSS transform - transformElement( vslide, vtransform ); - transformElement( vbackground, vtransform ); + toArray( hslide.querySelectorAll( 'section' ) ).forEach( function( vslide, v ) { + vslide.setAttribute( 'data-index-h', h ); + vslide.setAttribute( 'data-index-v', v ); - // Navigate to this slide on click - vslide.addEventListener( 'click', onOverviewSlideClicked, true ); - } + transformElement( vslide, 'translate3d(0, ' + ( v * slideHeight ) + 'px, 0)' ); + } ); - } - else { + } + } ); - // Navigate to this slide on click - hslide.addEventListener( 'click', onOverviewSlideClicked, true ); + // Layout slide backgrounds + toArray( dom.background.childNodes ).forEach( function( hbackground, h ) { + transformElement( hbackground, 'translate3d(' + ( h * slideWidth ) + 'px, 0, 0)' ); - } - } + toArray( hbackground.querySelectorAll( '.slide-background' ) ).forEach( function( vbackground, v ) { + transformElement( vbackground, 'translate3d(0, ' + ( v * slideHeight ) + 'px, 0)' ); + } ); + } ); - updateSlidesVisibility(); + } - layout(); + /** + * Moves the overview viewport to the current slides. + * Called each time the current slide changes. + */ + function updateOverview() { - if( !wasActive ) { - // Notify observers of the overview showing - dispatchEvent( 'overviewshown', { - 'indexh': indexh, - 'indexv': indexv, - 'currentSlide': currentSlide - } ); - } + var margin = 70; + var slideWidth = config.width + margin, + slideHeight = config.height + margin; + // Reverse in RTL mode + if( config.rtl ) { + slideWidth = -slideWidth; } + transformSlides( { + overview: [ + 'translateX('+ ( -indexh * slideWidth ) +'px)', + 'translateY('+ ( -indexv * slideHeight ) +'px)', + 'translateZ('+ ( window.innerWidth < 400 ? -1000 : -2500 ) +'px)' + ].join( ' ' ) + } ); + } /** @@ -1727,10 +1779,10 @@ // Only proceed if enabled in config if( config.overview ) { - dom.wrapper.classList.remove( 'overview' ); + overview = false; - // Move the background element back out - dom.wrapper.appendChild( dom.background ); + dom.wrapper.classList.remove( 'overview' ); + dom.wrapper.classList.remove( 'overview-animated' ); // Temporarily add a class so that transitions can do different things // depending on whether they are exiting/entering overview, or just @@ -1741,6 +1793,9 @@ dom.wrapper.classList.remove( 'overview-deactivating' ); }, 1 ); + // Move the background element back out + dom.wrapper.appendChild( dom.background ); + // Clean up changes made to slides toArray( dom.wrapper.querySelectorAll( SLIDES_SELECTOR ) ).forEach( function( slide ) { transformElement( slide, '' ); @@ -1753,8 +1808,12 @@ transformElement( background, '' ); } ); + transformSlides( { overview: '' } ); + slide( indexh, indexv ); + layout(); + cueAutoSlide(); // Notify observers of the overview hiding @@ -1793,7 +1852,7 @@ */ function isOverview() { - return dom.wrapper.classList.contains( 'overview' ); + return overview; } @@ -1943,7 +2002,7 @@ // If no vertical index is specified and the upcoming slide is a // stack, resume at its previous vertical index - if( v === undefined ) { + if( v === undefined && !isOverview() ) { v = getPreviousVerticalIndex( horizontalSlides[ h ] ); } @@ -1993,9 +2052,9 @@ document.documentElement.classList.remove( stateBefore.pop() ); } - // If the overview is active, re-activate it to update positions + // Update the overview if it's currently active if( isOverview() ) { - activateOverview(); + updateOverview(); } // Find the current horizontal slide and any possible vertical slides @@ -2108,6 +2167,10 @@ formatEmbeddedContent(); + if( isOverview() ) { + layoutOverview(); + } + } /** |