Canvas : réaliser une bannière animée en quelques lignes de code

| Gaëtan Renaudeau | Bovino |

Le HTML5 intègre de nouvelles technologies comme le canvas, une véritable API graphique destinée à remplacer le Flash dans les années à venir.

Ce tutoriel vise à présenter canvas comme une bibliothèque très simple d'utilisation et haut niveau grâce au langage JavaScript.

Il vous apprendra à réaliser une animation similaire à la bannière actuelle de mon blog en quelques lignes de code.

Il est volontairement ordonnancé de manière didactique, ainsi si vous maîtrisez les concepts, n'hésitez pas à avancer.

Cet article a été publié avec l'aimable autorisation de Gaëtan Renaudeau. L'article original peut être lu sur le blog de GreWeb : Tutoriel Canvas : Réaliser une bannière animée en quelques lignes de code.

Commentez ♪

- Titre : Canvas : réaliser une bannière animée en quelques lignes de code

- Auteurs : Gaëtan Renaudeau, Bovino

- Parution : 21 mai 2012

- Licence : Le contenu de cet article est rédigé par Gaëtan Renaudeau et est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.

Sommaire

- Prérequis

- Code de base (« skeleton template »)

- Deux choses notables

- Quelques notions de base du canvas

- La surface du canvas

- Le concept de contexte

- Les paramètres globaux du canvas

- Commençons à coder

- Chemins et traits simples

- Chemins et courbes de Bézier

- La notion de courbe de Bézier

- Application aux canvas

- bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

- Ajout de l'animation

- Approche linéaire

- Approche sinusoïdale

- Peaufinage

- Amélioration du style du trait

- Ajout de plusieurs courbes

- Aller plus loin

- Remerciements

Prérequis

Voir la vidéo : HTML Canvas pour les néophytes.

Code de base (« skeleton template »)

Nous allons travailler avec ce code HTML de base :

<!DOCTYPE html>
<html>
<head><title></title></head>
<body>
<canvas id="tuto" width="500" height="100" style="border: 1px solid;"></canvas>
<script>
var canvas = document.getElementById('tuto');
var ctx = canvas.getContext('2d');

// Le code JavaScript ira ici

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

Ce code nous servira dans tout le reste du tutoriel.

Deux choses notables

- Nous avons créé un élément canvas et indiqué ses dimensions (500×100). Pour mieux pouvoir les repérer, nous lui avons ajouté une bordure.

- En JavaScript, nous avons récupéré l'élément DOM puis le contexte 2d qui nous servira par la suite.

Quelques notions de base du canvas

La surface du canvas

Le canvas occupe une surface dont la dimension est définie par les paramètres width et height.

Pour ceux qui ne seraient pas familiers avec les bibliothèques graphiques, cette surface peut être vue comme un quadrillage de pixels sur deux dimensions : x variant de 0 à width et y variant de 0 à height.

Le point d'origine de ce repère orthonormé est situé dans le coin supérieur gauche du canvas.

Le concept de contexte

Le contexte 2d récupéré dans la variable ctx est en fait l'interface de programmation (API) de la bibliothèque graphique canvas.

C'est en quelque sorte l'intermédiaire entre le programmeur et la bibliothèque graphique.

Ainsi par exemple, si l'on veut dessiner un rectangle de dimension 20×10 à la position (5,6), il suffit d'écrire :

ctx.fillRect(5,6,20,10);

Les paramètres globaux du canvas

Pour dessiner, toute bibliothèque graphique a besoin de connaître un certain nombre de paramètres tels que la couleur du trait, la taille de la brosse, etc.

Plutôt que de devoir passer en paramètre ces informations aux fonctions du contexte, canvas met directement à disposition ces paramètres afin de pouvoir les modifier facilement.

Ainsi, nous pourrons définir la couleur de remplissage dans ctx.fillStyle() et la couleur de trait dans ctx.strokeStyle().

Commençons à coder

Avant d'attaquer l'animation, nous allons commencer à manier les outils de traçage.

Chemins et traits simples

Nous allons commencer par tracer un trait simple qui va traverser tout le canvas.
Essayez le code suivant :

// Commence à tracer un chemin.
ctx.beginPath();
// Définit le premier point de traçage à la position (0, 20).
ctx.moveTo(0, 20);
// Trace une ligne jusqu'à la position (canvas.width, 30).
// canvas.width désigne la largeur du canvas (500 dans notre exemple).
ctx.lineTo(canvas.width, 30);
// Indique au canvas de dessiner le chemin tracé depuis le beginPath.
ctx.stroke();

Voir le résultat.

Chemins et courbes de Bézier

La notion de courbe de Bézier

Une courbe de Bézier est définie par quatre points :

- deux points désignant le début et la fin du trait ;

- deux points (appelés poignées) permettant de contrôler la courbe.

Application aux canvas

Essayez le code suivant :

ctx.beginPath();
ctx.moveTo(0, 20);
ctx.bezierCurveTo(canvas.width/3, canvas.height, 2*canvas.width/3, 0, canvas.width, 20);
ctx.stroke();

Voir le résultat.

De la même façon, la procédure consiste à :

- commencer un chemin ;

- se placer à une certaine position ;

- effectuer un traçage (courbe de Bézier) ;

- terminer le traçage (ctx.stroke()).

Intéressons-nous plus particulièrement au traçage de la courbe de Bézier avec l'appel de ctx.bezierCurveTo().

bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

Cette fonction prend en argument les coordonnées du premier point de contrôle (cp1x, cp1y), du deuxième point de contrôle (cp2x, cp2y) et du point final (x, y). À noter que le point de début est celui sur lequel on s'est placé au moyen de moveTo().

Dans notre exemple, les deux points de contrôle sont placés ainsi :

Ajout de l'animation

Pour animer notre courbe de Bézier, nous allons faire varier les quatre points de notre courbe en fonction du temps.

En JavaScript, il y a trois moyens d'effectuer une animation :

- au moyen de setInterval() permettant d'appeler une fonction par intervalle de temps régulier ;

- au moyen de setTimeout() permettant d'appeler une fonction après un temps donné ;

- mise à jour (2011) : il est maintenant recommandé d'utiliser requestAnimationFrame() qui est l'équivalent de setTimeout() mais destiné à l'animation donc plus performant. Plus d'informations ici.

La première approche est parfaite pour une animation “statique”, avec peu d'interactions.

La seconde approche est intéressante lorsque l'animation doit être contrôlée (interaction). En effet, cette approche consiste à appeler setTimeout() à chaque cycle d'animation.

Nous choisirons d'utiliser setInterval(), plus simple et plus adaptée à notre tutoriel.

Approche linéaire

Commençons simplement par une évolution linéaire des points.
Essayez le code suivant :

// variable fonction du temps
var i = 0;
var cycle = function() {
// vide le canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
// y évolue par rebond entre 0 et canvas.height au cours du temps (linéarité)
var y = Math.abs(canvas.height-i%(2*canvas.height));
ctx.beginPath();
ctx.moveTo(0, y);
ctx.bezierCurveTo(canvas.width/3, canvas.height/2, 2*canvas.width/3, canvas.height/2, canvas.width, y);
ctx.stroke();
i++;
};
// lance le cycle chaque 30 millisecondes
setInterval(cycle, 30);

Voir le résultat.

Pour l'instant les poignées sont fixes et l'évolution linéaire de y donne un effet de rebond peu intéressant.

C'est pour cela que nous abandonnons l'idée d'une évolution linéaire des positions au cours du temps pour l'approche sinusoïdale.

Approche sinusoïdale

Comme nous l'avons vu, l'évolution linéaire n'est pas adaptée pour ce genre d'animation (effet de rebond). Il faudrait rendre l'animation plus fluide.

Pour cela, nous allons utiliser une évolution sinusoïdale des positions au cours du temps.
Essayez le code suivant :

// variable fonction du temps
var i = 0;
var cycle = function() {
ctx.clearRect(0,0,canvas.width,canvas.height);
var offset = i/20;
// y varie de 0 à canvas.height
var y = (Math.sin(offset)+1)*canvas.height/2;
// les poignées évoluent également de façon sinusoïdale
var cpy1 = (Math.cos(offset)+0.5)*canvas.height;
var cpy2 = canvas.height - cpy1;
ctx.beginPath();
ctx.moveTo(0, y);
ctx.bezierCurveTo(canvas.width/3, cpy1, 2*canvas.width/3, cpy2, canvas.width, y);
ctx.stroke();
i++;
};
setInterval(cycle, 30);

Voir le résultat.

Peaufinage

Amélioration du style du trait

Essayez le code suivant :

// couleur bleue avec opacité de 50 %
ctx.strokeStyle = 'rgba(80,150,240,0.5)';
ctx.lineWidth = 5; // épaisseur de trait de 5 pixels
var i = 0;
var cycle = function() {
ctx.clearRect(0,0,canvas.width,canvas.height);
var offset = i/20;
var y = (Math.sin(offset)+1)*canvas.height/2;
var cpy1 = (Math.cos(offset)+0.5)*canvas.height;
var cpy2 = canvas.height - cpy1;
ctx.beginPath();
ctx.moveTo(0, y);
ctx.bezierCurveTo(canvas.width/3, cpy1, 2*canvas.width/3, cpy2, canvas.width, y);
ctx.stroke();
i++;
};
setInterval(cycle, 30);

Voir le résultat.

Ajout de plusieurs courbes

Pour avoir un effet plus accrochant, nous allons ajouter plusieurs courbes de Bézier avec un décalage temporel entre elles.

Nous allons également attribuer plusieurs styles aux différentes courbes.

var numberOfLines = 5;
var i = 0;
var cycle = function() {
ctx.clearRect(0,0,canvas.width,canvas.height);
for(var j=0; j<numberOfLines; ++j) {
var offset = (i+j*10)/20;
// épaisseur variable en fonction de la ligne
ctx.lineWidth = 1+2*(numberOfLines-j);
// opacité variable en fonction de la ligne
ctx.strokeStyle = 'rgba(80,150,240,'+(j/5+0.1)+')';
var y = (Math.sin(offset)+1)*canvas.height/2;
var cpy1 = (Math.cos(offset)+0.5)*canvas.height;
var cpy2 = canvas.height - cpy1;
ctx.beginPath();
ctx.moveTo(0, y);
ctx.bezierCurveTo(canvas.width/3, cpy1, 2*canvas.width/3, cpy2, canvas.width, y);
ctx.stroke();
}
i++;
};
setInterval(cycle, 30);

Voir le résultat.

Aller plus loin

Il est possible de continuer encore plus loin en ajoutant l'évolution de plusieurs paramètres en fonction du temps.

Voici la démonstration finale :

var canvas = document.getElementById('tuto');
var ctx = canvas.getContext('2d');

var numberOfLines = 5;
var i = 0;
var cycle = function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for(var j=0; j<numberOfLines; ++j) {
ctx.lineWidth = 1+2*(numberOfLines-j);
ctx.strokeStyle = 'rgba(100,200,'+Math.floor(Math.abs(Math.cos(i/80)*256))+','+(j/5+0.1)+')';
var offset = (i+j*10*Math.abs(Math.cos(i/100)))/20;
var y = (Math.sin(offset)+1)*canvas.height/2;
var cpy1 = (Math.cos(offset)+0.5)*canvas.height;
var cpy2 = canvas.height - cpy1;
ctx.beginPath();
ctx.moveTo(0, y);
ctx.bezierCurveTo(canvas.width/3, cpy1, 2*canvas.width/3, cpy2, canvas.width, y);
ctx.stroke();
}
i++;
};
setInterval(cycle, 30);

Voir le résultat.

Nous avons ajouté :

- l'évolution de la couleur au cours du temps ;

- l'évolution du décalage entre les courbes au cours du temps.

Remerciements

Cet article a été publié avec l'aimable autorisation de Gaëtan Renaudeau. L'article original peut être lu sur le blog de Tutoriel Canvas : Réaliser une bannière animée en quelques lignes de code.

Nous tenons aussi à remercier Malikemal et ClaudeLELOUP pour leur relecture attentive de cet article.