Animation via les équations de robert penner

Soyez le premier à donner votre avis sur cette source.

Snippet vu 8 092 fois - Téléchargée 17 fois

Contenu du snippet

Cette source est une 'base' pour ceux et celles qui désirent créer leur moteur d'animations en Javascript.
Robert Penner, mathématicien en herbe plus connu dans l'univers du Flash, a mis au point il y a déjà quelques temps une serie d'équations permettant l'animation d'objets sous divers effets. On retrouve ces équations dans plusieurs librairies JS connues (mootools par exemple).

Mon exemple fournis 4 des effets les plus sympa et leur système d'utilisation. Vous trouverez l'ensemble des équations à l'adresse suivante :

http://www.robertpenner.com/easing/

Source / Exemple :


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Effets</title>
<style type="text/css">
	body{ font: 11px/16px Arial, "Trebushet MS", Helvetica; color: #333; }
	h2{ font-weight: bold; font-size: 14px; }
	td.libelle{ width: 180px; }
	td.valeur{ width: 100px; }
	td.inputs, td.select{ width: 100%; }
	#animation{ height: 32px; width: 32px; background: #aaccf6;	margin: 22px; }
</style>
</head>
<body>
<table>
	<tr>
		<td class="libelle">Durée de l'animation (en ms)</td>
		<td class="valeur"><input type="text" id="duration" value="800"/></td>
	</tr>
	<tr>
		<td class="libelle">Nombre de pixels à animer</td>
		<td class="valeur"><input type="text" id="nbPix" value="180"/></td>
	</tr>
	<tr>
		<td class="libelle">Transition</td>
		<td class="valeur">
			<select id="transition">
				<option value="linear" selected="selected">Lineaire</option>
				<option value="elastic">Elastique</option>
				<option value="bounce">Bonds</option>
				<option value="skid">Liquide</option>
			</select>
		</td>
	</tr>
	<tr>
		<td class="libelle">Valeur à modifier</td>
		<td class="valeur">
			<select id="cssRule">
				<option value="height" selected="selected">Hauteur</option>
				<option value="width">Largeur</option>
				<option value="both">Hauteur et largeur</option>
			</select>
		</td>
	</tr>
</table>

<input type="button" value="GO" onclick="animate()"/> <input type="button" value="Reset" onclick="reset()"/>

<div id="animation"></div>

<script type="text/javascript">
	function $(idObj){
		return document.getElementById(idObj);
	};
	
	var transitions = {
		linear: function(t, b, c, d){ return c*t/d + b; },
		elastic: function (t,b,c,d,a,p){
			if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
			if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
			else var s = p/(2*Math.PI) * Math.asin (c/a);
			return (a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b);
		},
		bounce: function(t,b,c,d){
			if((t/=d) < (1/2.75)) {
				return c*(7.5625*t*t) + b;
			}else if (t < (2/2.75)) {
				return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
			}else if (t < (2.5/2.75)) {
				return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
			}else{
				return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
			}
		},
		skid: function(t,b,c,d){
			var s = 1.70158;
			return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
		}
	};
	
	function reset(){
		$('animation').style.height = '32px';
		$('animation').style.width = '32px';
	};
	
	function animate(){
		var target = $('animation');
		var tmr = (1000/80); //assure une moyenne de 80 images par secondes
		var nbSteps = Math.round($('duration').value/tmr);
		var step = Math.abs(32 - $('nbPix').value)/nbSteps;
		var mapping = [];
		//On remplis un tableau contenant toutes les étapes de l'animation
		for(var i=1; i<=nbSteps; i++){
			mapping.push(transitions[$('transition').value](i*tmr, 32, $('nbPix').value - 32, $('duration').value));
		}
		var currentStep = 0;
		var timer = window.setInterval(function(){
			if(mapping[currentStep]){
				if($('cssRule').value=='both'){
					$('animation').style['height'] = mapping[currentStep]+'px';
					$('animation').style['width'] = mapping[currentStep]+'px';
				}else $('animation').style[$('cssRule').value] = mapping[currentStep]+'px';
				currentStep++;
			}else{
				window.clearInterval(timer);
				return;
			}
		}, tmr);
	};

</script>
</body>
</html>

A voir également

Ajouter un commentaire

Commentaires

Messages postés
262
Date d'inscription
vendredi 6 mai 2005
Statut
Membre
Dernière intervention
19 septembre 2014

ok , j'ai regardé a koi il correspondait, le a correspond a l étirement maximum, le p a l'élasticité

Cependant ma fonction permet de gérer les va et viens et la tension meme si les valeur doivent etre precise pour un resultat satisfaisant

J ai modifié la fonction de ROBERT PENNER pour kel prenne en compte le nbr de va et viens.
J'ai ajouté une fonction classic d'élasticité et de rebond.

voici le code a modifié
pour le select:

<option value="elasticKimjoa">elasticKimjoa</option>elasticClassic
<option value="elasticBounce">elasticBounce</option>
<option value="elasticClassic">elasticClassic</option>

pour l'objet transition

elasticClassic : function(t,b,c,d){
return c*(((1-Math.cos((t/=d) * Math.PI * 4)) * (1 - t)) + t)+b;
},
elasticKimjoa : function(t,b,c,d,te,bo,r){
// te=tension ,r=resistance, bo=rebont formule test
return c*(((1-Math.cos(Math.pow((t/=d),(1/(te || 1.5))) * Math.PI * (bo || 4))) * (1 - Math.pow(t,1/(t*(r || 10))))) + Math.pow(t,1/(t*(r || 10))))+b;
},
elastic: function (t,b,c,d,a,p){
t/=d;
if (!a)a=c*3;
//p=nbr de va et viens a etirement max reste tension
p=(p)?(p>1)?(c*10)/((p-1)/(d/1000)):(c*10)/(1/(d/1000)):(c*10)/(3/(d/1000));
if (a < Math.abs(c))
var s=p/4;
else
var s = p/(2*Math.PI) * Math.asin (c/a);
return (a*Math.pow(2,-10*(t)) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b);
},
elasticBounce: function (t,b,c,d,a,p){//p=bounce
var value=transitions.elastic(t,b,c,d,a,p);
if(Math.abs((value-b))>Math.abs(c))
return b+c-(value-c-b);
else return value;
}

je sais pas encore kel fonction je vais mettre dans ma librairie , j'aimerait bien pouvoir géré la tension

voila, a+
Messages postés
626
Date d'inscription
samedi 28 septembre 2002
Statut
Membre
Dernière intervention
18 mai 2009
3
Slt,

Pour l'équation 'élastique', tu as deux paramètres supplémentaires qui servent à gérer l'effet de l'animation.

function (t,b,c,d,a /!\ ,p /!\){
Messages postés
262
Date d'inscription
vendredi 6 mai 2005
Statut
Membre
Dernière intervention
19 septembre 2014

salut , je connais bien ses formules , pour les avoir utilisé dans mon propre script d'animation que je sortirais avec ma bibliothèques, qui me prend plus de temps que prévu. J'ai créer une formule d'élasticité en 'tatonant' pour permettre d'y inclure des options de résistance, nombre de va et viens, et de tension , je suis pas bon en math, et cette formule est sans doute fausse mais l'effet est pas mal , voici la fonction

elasticDown : function(t,s,e,obj){
return (e-s)*(((1-Math.cos(Math.pow(t,(1/obj.tension)) * Math.PI * obj.bounce)) * (1 - Math.pow(t,1/(t*obj.resistance)))) + Math.pow(t,1/(t*obj.resistance)))+s;
}
concernant les variables
t est le temp (compris entre 0 et 1)
s est la valeur de départ
e est la valeur d'arrivé
obj est l'objet avec les options

si un matheu pouvais me dire se kil en pense .

Pour les curieux http://www.dblog.free.fr/?act=article&art=64

bye
Messages postés
626
Date d'inscription
samedi 28 septembre 2002
Statut
Membre
Dernière intervention
18 mai 2009
3
"j'ai été obligé de rajouter un Singleton Fx.Listener"

Je ne connais pas ce singleton mais d'après son nom, c'est exactement ça. Faut créer un pseudo gestionnaire d'effets afin de supprimer les effets qui sont déjà en application.

"Animation est bien une classe vu que je l'utilise comme un constructeur."

Effectivement, j'ai lu en diagonale, toutes mes confuses.

"Le problème de gestion des timers dont tu parles est également présent dans la source que tu présentes ici."

Comme dis plus haut, ce n'est qu'une base pour l'utilisation des équations.
Messages postés
111
Date d'inscription
dimanche 23 mars 2003
Statut
Membre
Dernière intervention
1 août 2008

Utilisation de window.setInterval au lieu de interval
>> Alors ça, aucune idée, c'est une mauvaise (ou bonne ???) habitude.
A mon avis c'est facultatif et surtout je trouve que ça n'apporte pas grand chose au niveau de la lisibilité.
En revanche si tu souhaites remplacer la fonction alert par une méthode perso, ça me parait intéressant.
(En gros pour l'appel je ne m'en sers pas, mais pour la redéfinition je m'en sers)

>> tu n'as pas écris de classe mais deux objets.
Pourquoi deux objets ? -> ya une fonction (animate, qui créé un objet) et une définition de classe (Animation).
Animation est bien une classe vu que je l'utilise comme un constructeur.
Le problème de gestion des timers dont tu parles est également présent dans la source que tu présentes ici.
Je n'ai fait que la convertir à la mode Prototype, cependant j'ai ensuite tenté de reproduite ta démo avec cette source.
Le résultat : http://astre.henri.free.fr/creations_sandbox_mootools.php utilise les fichiers :
http://astre.henri.free.fr/js/effect.js
http://astre.henri.free.fr/js/myPrototype.js

Je serais curieux de voir comment tu as fait dans ta démo pour pouvoir comparer avec ma version.
En effet, j'ai été obligé de rajouter un Singleton Fx.Listener qui contient une liste de tous les effets appliqués à un élément.
Ya peut-être une méthode plus élégante ? Je n'ai pas pu comparer avec ta source car minified.js est assez illisible ;-)
Afficher les 11 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.