• 12 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 20/11/2019

Créez une animation riche

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Un exemple plus complexe

On se pose à présent la question de savoir comment, dans une animation un peu plus complexe, faire en sorte d'animer séparément plusieurs objets.

Cherchons par exemple à animer un petit carré de bas en haut avec un cercle qui tourne autour de ce carré.

On reprend les étapes vues lors du chapitre précédent :

  • définition du contexte ;

  • introduction d'une variable i sur laquelle nous allons itérer ;

  • introduction du timer ; ici, nous introduisons une petite modification par rapport à l'exercice précédent : pour définir le moment auquel l'animation va s'arrêter, nous n'allons pas utiliser la variable i comme précédemment, mais un timeout qui appellera une fonction d'arrêt après une période de temps définie, ici 20 secondes.

Détaillons à présent la fonction Animer() que le timer va lancer à intervalles réguliers.

<script>
/* canvas */
var monCanvas = document.getElementById('dessin');
if (monCanvas.getContext){
var ctx = monCanvas.getContext('2d');
} else {
alert('canvas non supporté par ce navigateur');
}
/* fonction de dessin */
function Animer() {
/* effaçage */
ctx.clearRect(0, 0, monCanvas.width,monCanvas.height);
/* translation du contexte et dessin du premier rectangle */
ctx.translate(2,2);
ctx.fillStyle = "blue";
ctx.fillRect(-10, -10, 20, 20);
/* rotation puis translation du contexte et dessin du cercle */
ctx.rotate( 0.5 );
ctx.translate(50,0);
/* arc : x, y, radius, startAngle, endAngle, antiClockwise */
ctx.beginPath();
ctx.arc(0, 0, 10, 0, 2 * Math.PI, false);
ctx.fillStyle = 'green';
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = '#003300';
ctx.stroke();
}
/* fonction d'arrêt */
function Stopper() {
clearInterval(inter);
}
/* timer */
var inter = setInterval(Animer, 100);
setTimeout(Stopper, 20000);
</script>

Que fait cette fonction ?

  • Première chose, elle va devoir effacer ce qui a été dessiné à l'itération précédente ;

  • ensuite, on translate le contexte de la valeur i suivant x et suivant y et on réalise le dessin du rectangle ;

  • puis on fait une rotation (en radian, par exemple i/50) du contexte (le rectangle n'est pas modifié, car la modification du contexte est effectuée postérieurement au dessin du rectangle).

Décomposition de la fonction Animer
Décomposition de la fonction Animer

Si l'on teste ce programme, on n'obtient pas tout à fait ce qui est recherché, comme vous pouvez le voir en lançant la vidéo ci-dessous :

La raison est simple : lorsque l'on entre à nouveau dans la fonction  Animer(), on part du contexte courant, c'est-à-dire celui que l'on a laissé à la fin de l'itération précédente.

Pour s'en convaincre, il suffit d'imaginer la suite des images de gauche lorsque l'on entre à nouveau dans la fonction Animer(). Il faudrait donc commencer à chaque fois par revenir au contexte initial avant d'appliquer de nouvelles translations et rotations ; en d'autres termes, à chaque itération, après avoir dessiné le cercle, il faudrait appliquer au contexte, dans l'ordre inverse, toutes les translations et rotations qu'on lui a appliquées. Ce qui semble bien compliqué pour une simple animation !

Cependant, si l'on revient en quelque sorte à l'état initial du contexte, il faut que les valeurs de translation et de rotation qui lui sont appliquées soient différentes d'une itération à l'autre, pour garantir l'illusion du mouvement. C'est pourquoi on introduit une variable i qui va être incrémentée à chaque itération, et servir comme valeur de translation et de rotation.

<script>
/* canvas */
var monCanvas = document.getElementById('dessin');
if (monCanvas.getContext){
var ctx = monCanvas.getContext('2d');
/* incrément */
var i=0;
} else {
alert('canvas non supporté par ce navigateur');
}
/* fonction de dessin */
function Animer() {
/* incrémentation */
i++;
/* sauvegarde de l'état du contexte */
ctx.save();
/* effaçage */
ctx.clearRect(0, 0, monCanvas.width,monCanvas.height);
/* translation du contexte et dessin du premier rectangle */
ctx.translate(i,i);
ctx.fillStyle = "blue";
ctx.fillRect(-10, -10, 20, 20);
/* rotation puis translation du contexte et dessin du cercle */
ctx.rotate( i/10 );
ctx.translate(50,0);
ctx.beginPath();
/* arc : x, y, radius, startAngle, endAngle, antiClockwise */
ctx.arc(0, 0, 10, 0, 2 * Math.PI, false);
ctx.fillStyle = 'green';
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = '#003300';
ctx.stroke();
/* retour à l'état précédent du contexte */
ctx.restore();
}
/* fonction d'arrêt */
function Stopper() {
clearInterval(inter);
}
/* timer */
var inter = setInterval(Animer, 100);
setTimeout(Stopper, 20000);
</script>

Première remarque : dans l'exemple proposé, nous aurions pu restaurer non pas le contexte initial, mais un contexte intermédiaire : le contexte après la première translation.

Je vous propose d'essayer cette option : dans ce cas, la valeur de la première translation peut rester à la valeur deux d'une itération à l'autre (puisqu'on part d'un contexte modifié) ; la valeur de la rotation, en revanche, doit rester une fonction de la variable i.

Seconde remarque : nous aurions pu également nous passer du  save()  et du  restore(), en dessinant le cercle à chaque fois avec un centre de coordonnées x et  y, tels que ce centre soit sur un cercle. Cependant, il était important de présenter ces deux fonctions sur un exemple simple.

Contextes précédemment sauvés
Contextes précédemment sauvés

Une succession de  restore()  permet de se déplacer dans la pile pour restaurer un de ces états.

Interaction entre formes

La suite de ce chapitre va nous permettre de découvrir comment deux formes peuvent interagir. On reprend l'exercice précédent en agrandissant le carré, de telle façon que le cercle intersecte avec ses coins.

Carré intersectant un disque
Carré intersectant un disque

Dans les exemples précédents, nous avons dessiné des formes les unes au-dessus des autres, dans l'ordre dans lequel elles sont dessinées. C'est le comportement par défaut.

Cependant, il est non seulement possible de dessiner les nouvelles formes derrière des formes existantes, mais également de définir la façon dont elles interagissent grâce à la propriété  globalCompositeOperation.

/* fonction de dessin */
function Animer() {
/* incrémentation */
i++;
ctx.globalCompositeOperation = 'lighter';
/* sauvegarde de l'état du contexte */
ctx.save();
/* effaçage */
ctx.clearRect(-100, -100, monCanvas.width-100,monCanvas.height-100);
/* translation du contexte et dessin du premier rectangle */
ctx.translate(i,i);
ctx.fillStyle = "blue";
ctx.fillRect(-40, -40, 80, 80);
/* rotation puis translation du contexte et dessin du cercle */
ctx.rotate( i/10 );
ctx.translate(50,0);
ctx.beginPath();
/* arc : x, y, radius, startAngle, endAngle, antiClockwise */
ctx.arc(0, 0, 10, 0, 2 * Math.PI, false);
ctx.fillStyle = 'green';
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = '#003300';
ctx.stroke();
/* retour à l'état précédent du contexte */
ctx.restore();
}

Testons par exemple le comportement destination-over : les nouvelles formes sont dessinées derrière le contenu existant du canvas. Essayez aussi lighter, darker ou xor.

Vous trouverez à la fin de ce chapitre un lien vous permettant d'essayer d'autres comportements.

Pour finir ce chapitre, nous vous proposons de réaliser une animation dans laquelle trois cercles descendent verticalement à une vitesse différente, comme ci-dessous :

Petit indice : commencez par définir une fonction générique qui sauve le contexte, dessine un cercle (dont la vitesse est passée en argument de cette fonction) et enfin restaure le contexte.

Bon travail !

En résumé

Nous venons de découvrir comment réaliser des animations complexes grâce à HTML5.

Dans la partie suivante, je vous propose de voir comment on peut introduire de l'interactivité dans une animation. Nous allons reprendre le concept d'événement JavaScript et l'adapter au contexte du canvas.

À tout de suite.

Exemple de certificat de réussite
Exemple de certificat de réussite