• Share on Google+

Nous allons voir comment faire l’animation style oscilloscope, présente sur mon portfolio en bas à gauche. J’ai mis un codepen en ligne et il a eu pas mal de vues, donc voila le tuto qui va avec !

Le codepen est dispo à cette adresse : http://codepen.io/tfarneau/pen/oDyGl

HTML

Pour la structure HTML, on a juste besoin de créer un canvas et de lui attribuer un id, de cette façon :

<canvas id="canvas"></canvas>

Pour ceux qui ne connaissent pas, un canvas est un élément HTML5 dans lequel on peut dessiner en pixel par pixel, grâce à une API javascript. Ça passe à peu près partout, sauf sur IE8. Voila le le lien du caniuse pour plus de détails sur la compatibilité.

CSS

On va maintenant styliser un peu notre page. Il est important de noter que CSS n’influe pas sur le contenu du canvas. La feuille de style permet de styliser la page, dont le conteneur du canvas, mais pas le contenu du canvas.

On va donc donner une couleur de fond à notre body, et une largeur et hauteur fixe à notre canvas pour pouvoir le center en absolute.

body{
background-color:#171D25;
}

canvas{
width:300px;
height:90px;
margin:auto;
top:0;
bottom:0;
left:0;
right:0;
position:absolute;
}

Javascript

Pour l’explication, mon graph ne sera pas un objet. Je pense en effet qu’il sera plus facile pour des débutants de comprendre si on ne s’encombre pas de notions de scope, avec des this qui risqueraient d’embrouiller. Vous trouverez cependant le code en orienté objet à la fin de cet article.

On va commencer par récupérer notre canvas, et à créer un context 2d à partir de ce canvas.

canvas = document.getElementById( 'canvas' );
context = canvas.getContext( '2d' );

On initialise ensuite 2 variables qui vont nous permettre de stocker la valeur en x du point, et les coordonnées de nos points. On initialise également une variable speed qui contiendra la vitesse de défilement.

var x = 0,
coords = new Array(),
speed = 8;

On commence ensuite par créer une fonction draw(), qui sera appelée à chaque fois qu’on devra dessiner notre graph.

function draw() {
}

On va ensuite clear le canvas pour effacer et remettre à zéro tous les pixels qui auront pu être modifiés lors de l’execution précédente de draw(). Canvas, c’est un peu comme une feuille de papier, si vous écrivez quelque chose dessus, ça va y rester jusqu’à ce que vous l’effaciez.

On va en profiter pour placer notre curseur au point d’abscisse 0 et d’ordonnée égale à la moitié de la hauteur de notre canvas (donc au milieu à gauche) dans notre canvas.

canvas.width = canvas.width;
context.moveTo(0, canvas.height/2);

À chaque execution de draw(), on veut que notre point avance de 8px vers la droite. On veut également que si x est supérieur à la largeur du canvas, les points défilent vers la gauche.

x+=speed;

if(x>canvas.width){
for(var i in coords){
coords[i].x=coords[i].x-speed;
}
}

On calcule ensuite des coordonnées aléatoires en y, et on prend la nouvelle valeur de x. Il ne nous reste qu’à pusher tout ça dans notre tableau coords.

coords.push({
x : x,
y : Math.floor(Math.random()*canvas.height/2)+canvas.height/2
});

Pour finir, on place tous les points, à partir du tableau coords, et on stylise un peu tout ça !

for(var i in coords){
context.lineTo(coords[i].x, coords[i].y);
}

context.strokeStyle="#9fdcf3";
context.lineWidth = 1;
context.shadowColor = '#9fdcf3';
context.shadowBlur = 10;

context.stroke();
context.closePath();

Il ne nous reste plus qu’une chose à faire, créer un setInterval qui nous permettra d’appeler draw() toutes les 100ms.

setInterval(draw,100);

Améliorations

Le code ci-dessus est largement perfectible. En faire un constructeur sera cohérent, pour pouvoir le rendre plus flexible et le réutiliser facilement (tout en utilisant x, speed, coords … comme des propriétés de l’instance de graph).

Il peut également être intéressant de remplacer le setInterval() par un setTimeOut() avec callback, ou par un requestAnimationFrame.

Code final

Voici le code final, tel qu’il est expliqué dans le tuto :

canvas = document.getElementById( 'canvas' );
context = canvas.getContext( '2d' );

var x = 0,
coords = new Array(),
speed = 8;

function draw() {

canvas.width = canvas.width;
context.moveTo(0, canvas.height/2);

x+=speed;

if(x>canvas.width){
for(var i in coords){
coords[i].x=coords[i].x-speed;
}
}

coords.push({
x : x,
y : Math.floor(Math.random()*canvas.height/2)+canvas.height/2
});

for(var i in coords){
context.lineTo(coords[i].x, coords[i].y);
}

context.strokeStyle="#9fdcf3";
context.lineWidth = 1;
context.shadowColor = '#9fdcf3';
context.shadowBlur = 10;

context.stroke();
context.closePath();

}

setInterval(draw,100);

Et le code en version objet, avec un setTimeOut() au lieu de setInterval() :

var graph = {};

graph.canvas = document.getElementById( 'canvas' ),
graph.context = canvas.getContext( '2d' ),
graph.x = 0,
graph.coords = new Array(),
graph.speed = 8;

graph.draw = function(delay) {

this.canvas.width = this.canvas.width;
this.context.moveTo(0, this.canvas.height/2);

this.x+=this.speed;

if(this.x>this.canvas.width){
for(var i in this.coords){
this.coords[i].x=this.coords[i].x-this.speed;
}
}

this.coords.push({
x : this.x,
y : Math.floor(Math.random()*this.canvas.height/2)+this.canvas.height/2
});

for(var i in this.coords){
this.context.lineTo(this.coords[i].x, this.coords[i].y);
}

this.context.strokeStyle="#9fdcf3";
this.context.lineWidth = 1;
this.context.shadowColor = '#9fdcf3';
this.context.shadowBlur = 10;

this.context.stroke();
this.context.closePath();

setTimeout(function(){
graph.draw(delay);
},delay);

}

graph.draw(100);