initial work for auto-animate

This commit is contained in:
Hakim El Hattab 2020-01-31 10:46:28 +01:00
parent 0dbdd89713
commit 8d89db32f6
4 changed files with 247 additions and 1 deletions

View file

@ -931,6 +931,17 @@ body {
transform: none; transform: none;
transition: none; } transition: none; }
/*********************************************
* AUTO ANIMATE
*********************************************/
.reveal section[data-auto-animate] {
transition: none; }
.reveal section[data-auto-animate] .auto-animate-target {
transition: all 0.7s ease;
-webkit-transform-origin: top left;
transform-origin: top left; }
/********************************************* /*********************************************
* PAUSED MODE * PAUSED MODE
*********************************************/ *********************************************/

View file

@ -990,6 +990,21 @@ $controlsArrowAngleActive: 36deg;
} }
/*********************************************
* AUTO ANIMATE
*********************************************/
.reveal section[data-auto-animate] {
transition: none;
}
.reveal section[data-auto-animate] .auto-animate-target {
transition: all 0.7s ease;
transform-origin: top left;
}
/********************************************* /*********************************************
* PAUSED MODE * PAUSED MODE
*********************************************/ *********************************************/

View file

@ -187,6 +187,20 @@
// - false: All iframes with data-src will be loaded only when visible // - false: All iframes with data-src will be loaded only when visible
preloadIframes: null, preloadIframes: null,
// Can be used to globally disable auto-animation
autoAnimate: true,
// CSS styles that auto-animations will animate between
autoAnimateStyles: [
'opacity',
'color',
'backgroundColor',
'border-top-left-radius',
'border-top-right-radius',
'border-bottom-left-radius',
'border-bottom-right-radius'
],
// Controls automatic progression to the next slide // Controls automatic progression to the next slide
// - 0: Auto-sliding only happens if the data-autoslide HTML attribute // - 0: Auto-sliding only happens if the data-autoslide HTML attribute
// is present on the current slide or fragment // is present on the current slide or fragment
@ -361,6 +375,10 @@
// Flags if the interaction event listeners are bound // Flags if the interaction event listeners are bound
eventsAreBound = false, eventsAreBound = false,
// A list of all elements that we have animated through
// auto-animations
autoAnimatedRollbacks = [],
// The current auto-slide duration // The current auto-slide duration
autoSlide = 0, autoSlide = 0,
@ -1390,6 +1408,12 @@
enablePreviewLinks( '[data-preview-link]:not([data-preview-link=false])' ); enablePreviewLinks( '[data-preview-link]:not([data-preview-link=false])' );
} }
// Reset all auto animated elements
autoAnimatedRollbacks.forEach( function( rollback ) {
rollback();
} );
autoAnimatedRollbacks = [];
// Remove existing auto-slide controls // Remove existing auto-slide controls
if( autoSlidePlayer ) { if( autoSlidePlayer ) {
autoSlidePlayer.destroy(); autoSlidePlayer.destroy();
@ -2300,7 +2324,7 @@
continue; continue;
} }
if( config.center || slide.classList.contains( 'center' ) ) { if( ( config.center || slide.classList.contains( 'center' ) ) ) {
// Vertical stacks are not centred since their section // Vertical stacks are not centred since their section
// children will be // children will be
if( slide.classList.contains( 'stack' ) ) { if( slide.classList.contains( 'stack' ) ) {
@ -2994,6 +3018,10 @@
cueAutoSlide(); cueAutoSlide();
if( slideChanged && previousSlide && currentSlide ) {
autoAnimate( previousSlide, currentSlide );
}
} }
/** /**
@ -3751,6 +3779,115 @@
} }
/**
* Runs an auto-animation between the given slides.
*
* @param {HTMLElement} fromSlide
* @param {HTMLElement} toSlide
*/
function autoAnimate( fromSlide, toSlide ) {
if( config.autoAnimate ) {
var prevTargets = {};
toArray( fromSlide.querySelectorAll( '[data-id]' ) ).forEach( function( element ) {
prevTargets[ element.getAttribute( 'data-id' ) ] = element;
} );
toArray( toSlide.querySelectorAll( '[data-id]' ) ).forEach( function( element ) {
var previousElement = prevTargets[ element.getAttribute( 'data-id' ) ];
if( previousElement ) {
autoAnimateElement( previousElement, element );
}
} );
}
}
/**
* Auto-animates the properties of an element from their original
* values to their new state.
*
* @param {HTMLElement} from
* @param {HTMLElement} to
*/
function autoAnimateElement( from, to ) {
var fromProps = getAutoAnimatableProperties( from ),
toProps = getAutoAnimatableProperties( to );
var delta = {
x: fromProps.x - toProps.x,
y: fromProps.y - toProps.y,
scaleX: fromProps.width / toProps.width,
scaleY: fromProps.height / toProps.height
};
to.style.transition = 'none';
to.style.transform = 'translate('+delta.x+'px, '+delta.y+'px) scale('+delta.scaleX+','+delta.scaleY+')';
to.classList.add( 'auto-animate-target' );
config.autoAnimateStyles.forEach( function( propertyName ) {
to.style[propertyName] = fromProps[propertyName];
} );
setTimeout( function() {
// Run the FLIP animation
to.style.transition = '';
to.style.transform = '';
config.autoAnimateStyles.forEach( function( propertyName ) {
to.style[propertyName] = toProps[propertyName];
} );
}, 1 );
}
/**
* Returns an object containing all of the properties
* that can be auto-animated for the given element
* and their respective values.
*/
function getAutoAnimatableProperties( element ) {
var properties = element._animatableProperties;
if( !properties ) {
properties = {};
// Position and size
properties.x = element.offsetLeft;
properties.y = element.offsetTop;
properties.width = element.offsetWidth;
properties.height = element.offsetHeight;
// Styles
config.autoAnimateStyles.forEach( function( propertyName ) {
properties[propertyName] = element.style[propertyName];
} );
// Cache the list of properties
element._animatableProperties = properties;
// Provide a method for rolling back this element to its
// pre auto-animated state.
autoAnimatedRollbacks.push( function( originalStyleAttribute ) {
element.setAttribute( 'style', originalStyleAttribute );
element.classList.remove( 'auto-animate-target' );
delete element._animatableProperties;
}.bind( null, element.getAttribute( 'style' ) ) );
}
return properties;
}
/** /**
* Should the given element be preloaded? * Should the given element be preloaded?
* Decides based on local element attributes and global config. * Decides based on local element attributes and global config.

View file

@ -0,0 +1,83 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reveal.js - Auto Animate</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="../../css/reveal.css">
<link rel="stylesheet" href="../../css/theme/black.css" id="theme">
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-auto-animate>
<h3 data-id="opacity-test">Opacity 1.0</h2>
</section>
<section data-auto-animate>
<h3 data-id="opacity-test" style="opacity: 0.2;">Opacity 0.2</h2>
</section>
<section data-auto-animate style="height: 600px">
<h3 style="opacity: 0.3; font-size: 18px;">SLIDE 1</h2>
<h2 data-id="title" style="margin-top: 260px;">Animate Anything</h2>
<div data-id="1" style="background: white; position: absolute; top: 150px; left: 16%; width: 60px; height: 60px;"></div>
<div data-id="2" style="background: white; position: absolute; top: 150px; left: 36%; width: 60px; height: 60px;"></div>
<div data-id="3" style="background: white; position: absolute; top: 150px; left: 56%; width: 60px; height: 60px;"></div>
<div data-id="4" style="background: white; position: absolute; top: 150px; left: 76%; width: 60px; height: 60px;"></div>
<!-- <p data-id="2" style="margin-top: 200px; border: 2px solid #999;">Text</p> -->
</section>
<section data-auto-animate style="height: 600px">
<h3 style="opacity: 0.3; font-size: 18px;">SLIDE 2</h2>
<h2 data-id="title" style="margin-top: 500px">With Auto Animate</h2>
<div data-id="1" style="background: cyan; position: absolute; bottom: 190px; left: 16%; width: 60px; height: 60px;"></div>
<div data-id="2" style="background: magenta; position: absolute; bottom: 190px; left: 36%; width: 60px; height: 160px;"></div>
<div data-id="3" style="background: yellow; position: absolute; bottom: 190px; left: 56%; width: 60px; height: 260px;"></div>
<div data-id="4" style="background: red; position: absolute; bottom: 190px; left: 76%; width: 60px; height: 360px;"></div>
<!-- <p data-id="2" style="margin-top: 200px; border: 2px solid #999; width: 50%;">Text</p> -->
</section>
<section data-auto-animate style="height: 600px">
<h3 style="opacity: 0.3; font-size: 18px;">SLIDE 3</h2>
<h2 data-id="title" style="margin-top: 500px; opacity: 0;">With Auto Animate</h2>
<div data-id="1" style="background: cyan; position: absolute; top: 50%; left: 50%; width: 400px; height: 400px; margin: -200px 0 0 -200px; border-radius: 400px;"></div>
<div data-id="2" style="background: magenta; position: absolute; top: 50%; left: 50%; width: 300px; height: 300px; margin: -150px 0 0 -150px; border-radius: 400px;"></div>
<div data-id="3" style="background: yellow; position: absolute; top: 50%; left: 50%; width: 200px; height: 200px; margin: -100px 0 0 -100px; border-radius: 400px;"></div>
<div data-id="4" style="background: red; position: absolute; top: 50%; left: 50%; width: 100px; height: 100px; margin: -50px 0 0 -50px; border-radius: 400px;"></div>
<!-- <p data-id="2" style="margin-top: 200px; border: 2px solid #999;">Text</p> -->
</section>
<section data-auto-animate style="height: 600px">
<h3 style="opacity: 0.3; font-size: 18px;">SLIDE 3</h2>
<h2 data-id="title" style="margin-top: 500px; opacity: 0;">With Auto Animate</h2>
<div data-id="1" style="background: red; position: absolute; top: 250px; left: 16%; width: 60px; height: 60px;"></div>
<div data-id="2" style="background: yellow; position: absolute; top: 250px; left: 36%; width: 60px; height: 60px;"></div>
<div data-id="3" style="background: magenta; position: absolute; top: 250px; left: 56%; width: 60px; height: 60px;"></div>
<div data-id="4" style="background: cyan; position: absolute; top: 250px; left: 76%; width: 60px; height: 60px;"></div>
<!-- <p data-id="2" style="margin-top: 200px; border: 2px solid #999;">Text</p> -->
</section>
</div>
</div>
<script src="../../js/reveal.js"></script>
<script>
// Full list of configuration options available here:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
center: true,
hash: true
});
</script>
</body>
</html>