JavaScript: monitorare le animazioni CSS

Short link

Il DOM dispone di tre eventi specifici che possiamo usare per monitorare le animazioni CSS. Un inizio (animationstart), una fine (animationend) ed una ripetizione (animationiteration). Il problema è che attualmente i browser implementano questi eventi attraverso i loro prefissi proprietari.

Per prima cosa definiamo una semplice animazione:


@-webkit-keyframes move {
	0% {
		left: 100px;
	}
	
	50% {
		width: 150px;
		height: 150px;
	}
	
	100% {
		width: 100px;
		height: 100px;
		left: 0;
	}
}

@-moz-keyframes move {
	0% {
		left: 100px;
	}
	
	50% {
		width: 150px;
		height: 150px;
	}
	
	100% {
		width: 100px;
		height: 100px;
		left: 0;
	}
}

@-ms-keyframes move {
	0% {
		left: 100px;
	}
	
	50% {
		width: 150px;
		height: 150px;
	}
	
	100% {
		width: 100px;
		height: 100px;
		left: 0;
	}
}

@keyframes move {
	0% {
		left: 100px;
	}
	
	50% {
		width: 150px;
		height: 150px;
	}
	
	100% {
		width: 100px;
		height: 100px;
		left: 0;
	}
}

.animate {
	-webkit-animation: move 2s ease-in 2s 3 alternate;
	-moz-animation: move 2s ease-in 2s 3 alternate;
	-ms-animation: move 2s ease-in 2s 3 alternate;
		animation: move 2s ease-in 2s 3 alternate;
}

Quindi definiamo una funzione di utility per uniformare i nomi degli eventi nei vari browser:


var prefixes = [ 'webkit', 'moz', 'MS', 'o', '' ];
var prefixedEvent = function( element, type, callback ) {
	for ( var p = 0; p < prefixes.length; p++ ) {
		if ( !prefixes[p] ) { 
			type = type.toLowerCase();
		}
		element.addEventListener( prefixes[p] + type, callback, false );
	}
}

A questo punto possiamo creare un unico handler che andrà ad eseguire un'azione diversa in base al tipo di evento:


var animationHandler = function( e ) {
	var item = document.createElement( 'li' ),
		evtType = e.type,
		evtStr = evtType.toLowerCase();
	
	if( evtStr.indexOf( 'start' ) != - 1 ) {
		item.innerHTML = 'Event started at time ' + e.elapsedTime;
	}
	
	if( evtStr.indexOf( 'end' ) != - 1 ) {
		item.innerHTML = 'Event ended at time ' + e.elapsedTime;
	}
	
	if( evtStr.indexOf( 'iteration' ) != - 1 ) {
		item.innerHTML = 'Now entering the loop at time ' + e.elapsedTime;
	}
  	
  	document.getElementById( 'log' ).appendChild( item );
};

Il codice finale sarà il seguente:


document.addEventListener( 'DOMContentLoaded', function() {

	var test = document.getElementById( 'test' );
	var run = document.getElementById( 'run' );
	
	prefixedEvent( test, 'AnimationStart', animationHandler );
	prefixedEvent( test, 'AnimationEnd', animationHandler );
	prefixedEvent( test, 'AnimationIteration', animationHandler );
	
	run.addEventListener( 'click', function() {
		test.className = 'animate';
	
	}, false );
	
	
	
}, false );