begin process at 2008 08 30 00:59:59
1 233 969 membres
8 nouveaux aujourd'hui
14 294 membres club

Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum.
Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

ANIMATION VIA LES ÉQUATIONS DE ROBERT PENNER


Information sur la source

Catégorie :Graphique Classé sous : animation, effets, equation Niveau : Débutant Date de création : 26/06/2008 Date de mise à jour : 26/06/2008 13:58:29 Vu : 2 388

Note :
9 / 10 - par 3 personnes
9,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (11)
Ajouter un commentaire et/ou une note

Description

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

  • <!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>
<!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>
26 juin 2008 13:58:29 :
Petit oubli corrigé...
  • signaler à un administrateur
    Commentaire de nickadele le 26/06/2008 20:56:09 administrateur CS 8/10

    Très bonne source au niveau du résultat et de l'effet !
    Vu que l'objet de cette source c'est de montrer les effets de ROBERT PENNER, un + aurait été des commentaires sur la méthode utilisée.

    Nickadele

  • signaler à un administrateur
    Commentaire de ralecul le 27/06/2008 00:06:18 9/10

    Bravo!

    Cette source me donne effectivement envie de faire mon moteur d'animation à la mootools.
    C'est une très bonne base pour découvrir les effets de Robert Penner.
    Cela permettra également à certain de découvrir les singletons en JS.

    La version de mootools n'utilise pas exactement les mêmes équations.
    En revanche, j'ai pu constaté que tu as scrupuleusement respecté la version AS de Robert Penner ;-)
    Ça aurait été sympa aussi de pouvoir choisir entre les modes easeIn, easeOut et easeInOut.
    La version de mootools est beaucoup plus simple pour cela par rapport aux équations fournies par Robert Penner.

    Commentaires sur le code :
    var step = Math.abs(32 - $('nbPix').value)/nbSteps;  -> tu ne te sers pas de cette variable.
    window.setInterval et window.clearInterval -> pourquoi tu spécifies window ? je suppose que tu n'utilises pas window.alert...
    corps de animate() -> j'aurais bien vu une version objet à la place (du genre : new Animate("animation", {duration: 800, type: linear}); )

  • signaler à un administrateur
    Commentaire de ralecul le 27/06/2008 00:38:31

    Désolé, je n'ai pas résisté à "prototyper" ta source :

    function animate() {
       new Animation("animation", {
          duration   : $('duration').value,
          transition : $('transition').value,
          amplitude  : $('nbPix').value,
          mode       : $('cssRule').value,
          initSize   : 32
       });
    };

    function Animation(div, options) {
       var _options    = options             || {};
       var _fps        = _options.fps        || 80;
       var _duration   = _options.duration   || 800;
       var _transition = _options.transition || "linear";
       var _amplitude  = _options.amplitude  || 180;
       var _mode       = _options.mode       || "both";
       var _initSize   = _options.initSize   || 42; //because 42 is the answer ;-)
       var _div        = $(div);

       var _interval   = 1000/_fps;
       var _nbSteps    = Math.round(_duration/_interval);

       var _mapping = [];
       for(var i=1; i<=_nbSteps; ++i)
          _mapping.push(transitions[_transition](i*_interval, _initSize, _amplitude - _initSize, _duration));

       var currentStep = 0;
       var timer = setInterval(iter, _interval);

       function iter() {
          if (_mapping[currentStep]) {
             if (_mode == 'both') {
                _div.style.height = _mapping[currentStep]+'px';
                _div.style.width  = _mapping[currentStep]+'px';
             }
             else {
                _div.style[_mode] = _mapping[currentStep]+'px';
             }
             currentStep++;
          }
          else {
             clearInterval(timer);
             return;
          }
       }
    }

    PS : c'est fait à la va-vite, ya peut-être quelques erreurs...
    PPS : Il suffit de remplacer la fonction animate par celle-ci et d'ajouter la classe Animation.

  • signaler à un administrateur
    Commentaire de XtremDuke le 27/06/2008 10:37:58

    "tu ne te sers pas de cette variable"

    >> Effectivement je ne m'en sers pas. Il s'agit en fait d'un simple copie/colle d'un travaille personnel.

    "pourquoi tu spécifies window "

    >> Alors ça, aucune idée, c'est une mauvaise (ou bonne ???) habitude.

    "Il suffit de remplacer la fonction animate par celle-ci et d'ajouter la classe Animation"

    >> tu n'as pas ecris de classe mais deux objets.

    Pour parler de ta 'classe', il te faut rajouter une gestion des timers. Sinon, tu vas avoir des surprises si tu utilises cette fonction sur des 'mouseover'.

    Remarque : Cette base que j'ai fournis et normalement ecrit sous forme de classe ds un projet perso. Voir :
    http://joof-api.net/demo.html

  • signaler à un administrateur
    Commentaire de lakichemole le 27/06/2008 13:54:08

    Il manque l'include de prototype dans ton exemple :/

  • signaler à un administrateur
    Commentaire de lakichemole le 27/06/2008 13:56:32 10/10

    à non au temps pour moi, erreur de copier coller :)

  • signaler à un administrateur
    Commentaire de ralecul le 27/06/2008 17:34:53

    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 ;-)

  • signaler à un administrateur
    Commentaire de XtremDuke le 27/06/2008 20:28:45

    "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.

  • signaler à un administrateur
    Commentaire de Kimjoa le 28/06/2008 12:06:12

    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



  • signaler à un administrateur
    Commentaire de XtremDuke le 28/06/2008 18:23:40

    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 /!\){

  • signaler à un administrateur
    Commentaire de Kimjoa le 28/06/2008 22:12:19

    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+

Ajouter un commentaire

Pub



Appels d'offres

Recherche developpeur ...
Budget : 700€
SITE MARCHAND LOCATION...
Budget : 3 000€
SITE MARCHAND POUR HOTEL
Budget : 4 000€

CalendriCode

Août 2008
LMMJVSD
    123
45678910
11121314151617
18192021222324
25262728293031

Téléchargements

Logiciels à télécharger sur le même thème :

Boutique

Boutique de goodies CodeS-SourceS