diff options
-rw-r--r-- | css/reveal.css | 9 | ||||
-rw-r--r-- | css/reveal.scss | 12 | ||||
-rw-r--r-- | js/reveal.js | 81 | ||||
-rw-r--r-- | test/examples/auto-animate.html | 2 |
4 files changed, 94 insertions, 10 deletions
diff --git a/css/reveal.css b/css/reveal.css index a98a752..2d19d61 100644 --- a/css/reveal.css +++ b/css/reveal.css @@ -1227,6 +1227,15 @@ body { transition-duration: 1200ms; } /********************************************* + * AUTO ANIMATE + *********************************************/ +.reveal section[data-auto-animate] [data-auto-animate-unmatched="fade-in"] { + opacity: 0; } + +.reveal section[data-auto-animate="running"] [data-auto-animate-unmatched="fade-in"] { + opacity: 1; } + +/********************************************* * OVERVIEW *********************************************/ .reveal.overview { diff --git a/css/reveal.scss b/css/reveal.scss index 335b96b..1d14a02 100644 --- a/css/reveal.scss +++ b/css/reveal.scss @@ -1311,6 +1311,18 @@ $controlsArrowAngleActive: 36deg; /********************************************* + * AUTO ANIMATE + *********************************************/ + +.reveal section[data-auto-animate] [data-auto-animate-unmatched="fade-in"] { + opacity: 0; +} +.reveal section[data-auto-animate="running"] [data-auto-animate-unmatched="fade-in"] { + opacity: 1; +} + + +/********************************************* * OVERVIEW *********************************************/ diff --git a/js/reveal.js b/js/reveal.js index 1bb9842..765ce3d 100644 --- a/js/reveal.js +++ b/js/reveal.js @@ -1431,9 +1431,8 @@ toArray( dom.slides.querySelectorAll( '[data-auto-animate]:not([data-auto-animate=""])' ) ).forEach( function( element ) { element.dataset.autoAnimate = ''; } ); - toArray( dom.wrapper.querySelectorAll( '[data-auto-animate-target]' ) ).forEach( function( element ) { - delete element.dataset.autoAnimateTarget; - } ); + + removeEphemeralAutoAnimateAttributes(); if( autoAnimateStyleSheet && autoAnimateStyleSheet.parentNode ) { autoAnimateStyleSheet.parentNode.removeChild( autoAnimateStyleSheet ); @@ -3849,10 +3848,8 @@ autoAnimateStyleSheet.innerHTML = ''; } - // Clean up from previous animations - toArray( document.querySelectorAll( '[data-auto-animate-target]' ) ).forEach( function( element ) { - delete element.dataset.autoAnimateTarget; - } ); + // Clean up after prior animations + removeEphemeralAutoAnimateAttributes(); var slideOptions = getAutoAnimateOptions( toSlide, { @@ -3868,9 +3865,21 @@ toSlide.dataset.autoAnimate = 'pending'; // Inject our auto-animate styles for this transition - autoAnimateStyleSheet.innerHTML = getAutoAnimatableElements( fromSlide, toSlide ).map( function( elements ) { + var css = getAutoAnimatableElements( fromSlide, toSlide ).map( function( elements ) { return getAutoAnimateCSS( elements.from, elements.to, elements.options || {}, slideOptions, autoAnimateCounter++ ); - } ).join( '' ); + } ); + + // If the slide is configured to animate unmatched elements we + // need to flag them + if( toSlide.dataset.autoAnimateUnmatched ) { + getUnmatchedAutoAnimateElements( toSlide ).forEach( function( unmatchedElement ) { + unmatchedElement.dataset.autoAnimateUnmatched = 'fade-in'; + } ); + + css.push( '.reveal [data-auto-animate="running"] [data-auto-animate-unmatched] { transition: all '+ (slideOptions.duration*0.8) +'s ease '+ (slideOptions.duration*0.2) +'s; }' ); + } + + autoAnimateStyleSheet.innerHTML = css.join( '' ); // Start the animation next cycle requestAnimationFrame( function() { @@ -3880,6 +3889,22 @@ } /** + * Removes all attributes that we temporarily add to slide + * elements in order to carry out auto-animation. + */ + function removeEphemeralAutoAnimateAttributes() { + + toArray( dom.wrapper.querySelectorAll( SLIDES_SELECTOR + ':not(.stack) [data-auto-animate-target]' ) ).forEach( function( element ) { + delete element.dataset.autoAnimateTarget; + } ); + + toArray( dom.wrapper.querySelectorAll( SLIDES_SELECTOR + ':not(.stack) [data-auto-animate-unmatched]' ) ).forEach( function( element ) { + delete element.dataset.autoAnimateUnmatched; + } ); + + } + + /** * Auto-animates the properties of an element from their original * values to their new state. * @@ -4140,6 +4165,44 @@ } /** + * Returns a all elements within the given scope that should + * be considered unmatched in an auto-animate transition. If + * fading of unmatched elements is turnded on, these elements + * will fade when going between auto-aniamted slides. + * + * Note that parents of auto-animate targets are NOT considerd + * unmatched since fading them would break the auto-animation. + * + * @param {HTMLElement} rootElement + * @return {Array} + */ + function getUnmatchedAutoAnimateElements( rootElement ) { + + return [].slice.call( rootElement.children ).reduce( function( result, element ) { + + // If the element is auto-animated we can stop looking at this tree + if( !element.hasAttribute( 'data-auto-animate-target' ) ) { + + // If this element contains an auto-animated element it's considered + // a match since we can't fade it without affecting the inner + // auto-animate target + if( !element.querySelector( '[data-auto-animate-target]' ) ) { + result.push( element ); + } + else { + // Keep looking down this tree + result = result.concat( getUnmatchedAutoAnimateElements( element ) ); + } + + } + + return result; + + }, [] ); + + } + + /** * Should the given element be preloaded? * Decides based on local element attributes and global config. * diff --git a/test/examples/auto-animate.html b/test/examples/auto-animate.html index bb982f5..a70e2d2 100644 --- a/test/examples/auto-animate.html +++ b/test/examples/auto-animate.html @@ -19,7 +19,7 @@ <div class="slides"> - <section data-auto-animate> + <section data-auto-animate data-auto-animate-unmatched="fade"> <h3>Auto-Animate Example</h3> <p>This will fade out</p> <img src="assets/image1.png" style="height: 100px;"> |