Dans ce chapître, nous allons créer des élements animés toujours en utilisant les fonctionnalités de Fabric.js. Comme précedemment, il vous est demandé de créer une page index.html disposant :
<canvas>
,Tous les objets créés en utilisant Fabric.js peuvent être animés à l’aide de la méthode animate.
Le code ci-dessous permet de créer un rectangle et de la faire bouger de gauche à droite :
const rect1 = new fabric.Rect({
left: 100,
top: 100,
fill: 'red',
width: 20,
height: 20
});
rect1.animate(
'left',
'+=100',
{
onChange: canvas.renderAll(canvas)
}
);
Testez cette animation pour modifier différentes propriétés du rectangle (position, dimensions, couleur, …)
Créez un cercle et effectuez différents textes
Positionnez votre rectangle en haut de votre canvas, et faites en sorte qu’il tombe jusqu’en bas.
A la suite de la propriété onChange
, ajoutez les propriétés :
duration: 300,
easing: fabric.util.ease.easeOutBounce
Par défaut, la durée de l’animation est de 500 ms, modifiez-la à souhait. La propriété easing peut pren,dre différentes valeurs, modifiant le comportement de l’animation. Testez différentes possibilités.
Faites en sorte que le cercle se déplace latéralement, et rebondisse sur les parois du canvas.
La fonction canvas.renderAll()
réaffiche systématiquement l’ensemble des objets présents, ce qui peut être pénalisant. Fabric.js
propose une fonction fabric.util.animate qui possède différents arguments dont onChange
qui est la fonction vue précédemment et onComplete
qui est une fonction qui s’exécute lorsque l’animation est terminée.
Vous pouvez tester le code suivant, qui vous permet de bien comprendre le comportement de cette fonction :
let cpt=0;
function animate() {
fabric.util.animate({
duration: 200,
onChange: () => {
canvas.renderAll();
console.log(cpt++);
},
onComplete: () => {
console.log("terminé");
}
});
}
animate();
Modifiez la valeur de la propriété duration
et observez ce qui s’affiche dans la console.
Testez le code suivant :
let cpt=0;
let n=0;
function animate() {
fabric.util.animate({
duration: 200,
onChange: () => {
canvas.renderAll();
console.log(cpt++);
},
onComplete: () => {
if(n<3) animate();
console.log("fin du tour " + n++);
}
});
}
animate();
Vous observez que l’animation est relancée tant que la variable n
reste inférieure à 3. Il suffit de supprimer cette condtion pour que votre animation devienne infinie.
n
afin d’obtenir une animation infinie.mouse:over
) et s’arrête lorsque le pointeur sort du canvas (évènement mouse:out
). Ecrivez le code qui gère ces deux évènements et permette de déclencher ou d’arrêter le mouvement.dX
et verticalement d’une distance dY
. Lorsqu’il touche une paroi, dX
devient -dX
, ou dY
devient -dY
selon les cas.La fonction fabric.util.requestAnimFrame permet de gérer plus finement les animations en contrôlant précisément les intervalles de temps. Cette fonction permet juste d’utiliser la fonction requestAnimationFrame de JavaScript.
Testez le code suivant qui permet de comprendre comment cela fonctionne :
let cpt = 0;
let startTime = Date.now(),
prevTime = startTime;
function animate() {
let time = Date.now();
if (time > prevTime + 1000) {
prevTime = time;
console.log("time=", time, "cpt=", cpt++);
}
if (cpt < 3) fabric.util.requestAnimFrame(animate, canvas.getElement());
else console.log("stop");
canvas.renderAll();
}
console.log("hello!!");
animate();
startTime
, prevTime
et time
.cpt
.requestAnimFrame
s’exécute-t-elle?animate
est-elle lancée?canvas.renderAll
?Créez un cadre dans lequel circulent deux balles rebondissantes
Lorsque ces balles se percutent, il faut faire en sorte qu’elles repartent dans des directions cohérentes. Le code étant plus complexe, ci-dessous une méthode qui permet de modifier les trajectoires de deux balles qui se percutent. Supposons que ces balles soient définies par des objets b1
et b2
avec les propriétés suivantes :
x
, y
: les positions en abscisse et ordonnéedeltaX
et deltaY
: le déplacement des balles (nombre de pixels) en abscisse et en ordonnée à chaque unité de temps handleCollision(b1, b2) {
let norme = v => Math.hypot(v.x, v.y);
let somme = (u, v) => {
return {x: u.x + v.x, y: u.y + v.y}
};
let mul = (k, v) => {
return {x: k * v.x, y: k * v.y}
};
let n = {x: b2.x - b1.x, y: b2.y - b1.y};
let q = Math.sqrt(Math.pow(n.x, 2) + Math.pow(n.y, 2));
let un = {x: n.x / q, y: n.y / q};
let ut = {x: -un.y, y: un.x};
let v1 = {x: b1.deltaX, y: b1.deltaY};
let v2 = {x: b2.deltaX, y: b2.deltaY};
let v_1n = (Math.pow(norme(somme(un, v1)),2) - Math.pow(norme(un),2) - Math.pow(norme(v1),2))/2;
let v_1t = (Math.pow(norme(somme(ut, v1)),2) - Math.pow(norme(ut),2) - Math.pow(norme(v1),2))/2;
let v_2n = (Math.pow(norme(somme(un, v2)),2) - Math.pow(norme(un),2) - Math.pow(norme(v2),2))/2;
let v_2t = (Math.pow(norme(somme(ut, v2)),2) - Math.pow(norme(ut),2) - Math.pow(norme(v2),2))/2;
let vp_1n = mul(v_2n, un);
let vp_1t = mul(v_1t, ut);
let vp_2n = mul(v_1n, un);
let vp_2t = mul(v_2t, ut);
let vp_1 = somme(vp_1n, vp_1t);
let vp_2 = somme(vp_2n, vp_2t);
b1.deltaX = vp_1.x;
b1.deltaY = vp_1.y;
b2.deltaX = vp_2.x;
b2.deltaY = vp_2.y;
}
Attention : Ce code vous permettra de modifier correctement les trajectoires des balles mais ne règlera pas tous vos problèmes. Il vous restera à l’adapter à votre code et, peut-être, à l’améliorer légèrement.
Remarque : Si vous souhaitez comprendre ce code, je vous conseille la lecture de l’article suivant qui explique en détails les calculs avec en prime la possibilité de gérer des balles de masses différentes.