Avec l'API Canvas on peut réaliser des animmations complexes voire des jeux.
Ci-dessous un document HTML contenant un canevas qui tient lieu de diaporama.
Cliquez sur le bouton de commmande pour mettre fin au diaporama.
Notez que l'élément button appelle une instruction JS sur clic.
La variable entier contient un entier compris entre 1 et 35 qui est généré de façon aléatoire.
Une image reste affichée deux secondes (2000 millisecondes) avant qu'elle ne soit effacée puis remplacée par une nouvelle.
Dans cette application on superpose parfaitement deux 'toiles'. C'est le principe des 'calques'.
La difficulté est d'ordre CSS ; vous êtes obligé d'utiliser le positionnement absolu
pour empiler les différents 'calques' et les centrer.
Cliquez dans le cadran pour lancer la trotteuse.
Pour que les deux toiles se superposent parfaitement elles doivent être positionnées en absolu.
La règle de style relative aux éléments CANVAS peut paraitre un peu compliquée ...
Deux fonctions : une pour remplir le canevas du dessous et une autre pour dessiner dans le "calque" du dessus.
Pour dessiner des ronds et des aiguilles qui tournent autour d'un axe, il faut que l'origine du canevas soit son centre.
D'ou l'instruction : translate(X/2,Y/2).
Ci-dessous un document HTML contenant une 'toile' qui affiche une horloge.
Deux fois par minute il y a actualisation de l'affichage.
Règles de style : les canevas seront superposés.
Notez dans la partie HEAD l'instruction : meta http-equiv="Refresh" content="30"
Je ne vous communique pas le code de la fonction qui remplit le premier canevas.
Il suffit de vous inspirer de l'application "trotteuse" évoquée plus haut dans ce chapitre.
...New Date() : création d'un objet Date qui contient l'instant présent.
Notez les commandes ctx.save() & ctx.restore(). En effet avant toute rotation pour afficher les minutes, Il
faut restaurer le contexte initial (rotation de -90% pour que l'axe des X soit vertical).
Le format d'affichage de l'heure est : hh:mm:ss (toujours deux chiffres pour l'heure, les minutes et les secondes).
Vous devez être capable réaliser cette animation.
Attention on ne peut pas imaginer une recharge de la page chaque seconde, le serveur web serait trop sollicité.
Revoyez le chapitre "Insertion de textes et ombrages" pour revoir toutes les propriétés et méthodes qui gèrent le texte inséré dans
un canevas : texAlign, textBaseline, font, ... fillText(), strokeText, ...
Pour afficher l'heure courante au format francophone utilisez la méthode toLocaleTimeString().
Le script pour dessiner et animer l'horloge digitale est très succinct
grâce à l'utilisation des outils précités.
Il n'y a plus qu'afficher les variables "heure & cejour" dans le canevas.
Ci-dessous un document HTML qui affiche le jeu de squash.
La balle et la raquette ne sont pas ombrées mais ça serait un jeu d'enfant.
L'élément canevas définit un repère de 400 par 400.
Il est orienté objet !
On définit deux objets : la balle et la raquette.
Le jeu est déclenché par un clic dans le canevas.
La boucle de jeu est itérée tous les 50 millisecondes donc 20 fois par seconde : var stop = setInterval(boucle_jeu,50).
Déplacement de la raquette : pour des explications concernant la programmation des touches du clavier,
je vous renvoie au chapitre précédent.
la balle ne peut sortir du canevas :
Gestion de l'interception de la balle par la raquette :
Dans le cadre d'un jeu il peut être plus pratique de déplacer un objet avec la souris plutôt que via le clavier.
Ce document affiche la position X & Y de la souris dans la fenêtre et dans le canevas.
...canvas id ="canvas" width ="800" height = "300" onmousemove="info(event)" ... </canvas>
Nouveauté JS : var element = canvas.getBoundingClientRect() ; la variable element référence le canevas.
On peut ensuite appliquer à l'objet element les propriétés left, top, right, bottom, widht, height.
Pour calculer la position X du pointeur dans le canevas il faut retirer de sa position X dans la fenêtre la position 'left' du
canevas.
À partir du script précédent il est facile de créer un programme qui déplace une forme du canevas via la souris.
Cliquez dans le canevas puis déplacez la souris et observez
La balle est initialement au centre du canevas.
L'élément canvas définit un repère de 600 par 600 avec l'attribut ID.
J'ai recouru à la POO : création d'un objet nommé "balle".
Rien n'interdit d'utiliser l'API Canvas avec le framework jQuery.
Ci-dessous un document HTML contenant une 'toile'.
Déplacez la souris dans la fenêtre ;
Vous pouvez me contacter via Facebook pour questions & suggestions :
Page Facebook relative à mon site
Des animations plus complexes & jeux
Je présente dans ce chapitre quelques astuces pour simplifier la programmation des animations et jeux.
Un diaporama automatique
Toutes les deux secondes affichage d'une nouvelle photo sexy.
Remarquez que les photos sont toujours bien centrées dans le canevas et qu'elles ne sont jamais déforméés.
Par aillleurs elles apparaissent avec deux filtres : effet sépia et ombrage.
Actualisez la page pour relancer l'animation.
Le code HTML
Le script
var routine;
function f1()
{
var canevas = document.querySelector('canvas');
var contexte = canevas.getContext('2d');
contexte.filter ="sepia(1) drop-shadow(10px 10px 3px gray)";
var X =canevas.width;
var Y =canevas.height;
function ajout()
{
contexte.clearRect(0,0,X,Y);
var image = new Image();
var reel = Math.random() ;
var entier = Math.ceil(reel*35) ;
switch(entier)
{
case 1 : image.src ="../images/bikini.jpg" ; break;
case 2 : image.src ="../images/bikini2.jpg" ; break;
...
case 35 : image.src ="../images/bikini35.jpg" ; break;
} // fin switch
image.onload =function()
{
largeur =image.width;
hauteur =image.height;
ratio = hauteur /largeur;
largeur_fixee = X/100*60;
hauteur_fixee = largeur_fixee * ratio;
var x = (X-largeur_fixee)/2;
var y = (Y-hauteur_fixee)/2;
contexte.drawImage(image,x,y,largeur_fixee,hauteur_fixee) ;
} // fin fonction anonyme
} // fin fonction ajout
routine = setInterval(ajout,2000);
} // fin f1
f1(); // appel f1
On récupère dans les variables largeur & hauteur les dimensions de l'image chargée. A partir de ces infos on calcule
les dimensions d'affichage de l'image et la position de son coin supérieur gauche afin qu'elle soit toujours centrée dans le canevas
et jamais déformée.
La trotteuse
Cette solution CSS & HTML permet de simplifier considérablement le travail du développeur :
Ci-dessous une document HTML qui intègre deux canevas parfaitement surperposés
Le code CSS & HTML
Le "calque" du dessous peut avoir une image ou couleur de fond. Celui du dessus est par défaut transparent.
Notez que les deux canevas s'affichent avec une largeur de 60% dans leur conteneur.
Pour qu'ils soient centrés dans leur élément parent, il faut donc règler la propriété left à 50% et
la propriété margin-left à -30% (moitié de leur largeur d'affichage).
La propriété CSS position
Le script
function f1()
// pour dessiner dans le premier canevas
{
var canvas = document.querySelector("#canvas1");
var ctx = canvas.getContext("2d");
var X =canvas.width;
var Y =canvas.height;
ctx.translate(X/2,Y/2);
// l'origine du canevas devient son centre
ctx.strokeStyle = "gold";
ctx.lineWidth = 4;
// marques heures
for (var i=0;i<12;i++)
{
ctx.beginPath();
// un trait tous les 30°
ctx.rotate(Math.PI/180 * 30);
ctx.moveTo(80,0);
ctx.lineTo(100,0);
ctx.stroke();
}
// marques minutes
ctx.lineWidth = 2;
for (i=0;i<60;i++)
{
ctx.beginPath();
// un trait tous les 6°
ctx.rotate(Math.PI/180 *6);
ctx.moveTo(90,0);
ctx.lineTo(100,0);
ctx.stroke();
}
} // fin f1
f1();
function f2()
// pour dessiner dans le deuxième canevas
{
var canvas = document.querySelector("#canvas2");
var contexte = canvas.getContext("2d");
var X = canvas.width;
var Y = canvas.height;
var stop;
contexte.strokeStyle ="black";
contexte.translate(X/2,Y/2);
// l'origine du canevas devient son centre
canvas.onclick = function() {stop = setInterval(deplacer,1000);}
// une fois par seconde
canvas.onmouseout = function() {clearInterval(stop);}
function deplacer()
{
contexte.rotate(Math.PI/180 *6);
contexte.lineWidth =3;
contexte.beginPath();
contexte.moveTo(0,0);
contexte.lineTo(0,-100);
contexte.closePath();
contexte.stroke();
contexte.clearRect(-X/2,-Y/2,X/2,Y/2);
}
} //fin f2
f2();
Dans le "calque" du dessous je dessine le cadran horaire.
Dans le canevas de dessus je dessine et anime la "trotteuse".
Mais attention il faut adapter le code de la commande clearRect() en conséquence pour tenir
compte du changement d'origine : clearRect(-X/2,-Y/2,X/2,Y/2)
Une belle horloge
Le rendu
Le code
Code HTML & CSS
Ce qui veut dire que toutes les trente secondes la page est rechargée ; donc le script exécuté et la nouvelle heure affichée.
Le script
...
// pour remplir le deuxième canevas
function f2()
{
let canvas = document.querySelector("#canevas2");
let ctx = canvas.getContext("2d");
let X = canvas.width;
let Y = canvas.height;
ctx.translate(X/2,Y/2);
// l'origine du canevas devient son centre
ctx.strokeStyle ="black";
ctx.lineCap ="round";
let maintenant = new Date();
var secondes = maintenant.getSeconds();
let minutes = maintenant.getMinutes();
let heures = maintenant.getHours();
heures = heures >=12 ? heures-12 : heures;
// passer de h 24 à h12
ctx.rotate(-Math.PI/180*90);
ctx.save();
// aiguille des heures
heure_fraction = (heures + minutes/60);
ctx.rotate(Math.PI/180 * 30 * heure_fraction);
ctx.lineWidth = 10;
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(80,0);
ctx.stroke();
// aiguille des minutes
ctx.restore();
ctx.rotate(Math.PI/180 * 6 * minutes);
ctx.lineWidth = 6;
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(100,0);
ctx.stroke();
} // fin f2
f2() // appel de f2
Analyse du script
... maintenant.getHours() : récupération de l'heure sous forme d'un entier
ctx.translate(X/2,Y/2) : l'origine du canevas devient son centre.
ctx.rotate(-Math.PI/180*90) : l'axe X du canevas doit être orienté vers le haut avant toute
application d'une nouvelle rotation.
heure = heure >=12 ? heure-12 : heure : heure 24 doit être convertie en heure 12.
heure_fraction = (heures + minutes/60) : si il 7 heures-10 l'aiguille des heures doit être plus près de 7
que de 6.
ctx.rotate(Math.PI/180 * 30 * heure_fraction) : une heure correspond à 30° (360 /12) sur un cadran horaire.
ctx.rotate(Math.PI/180 * 6 * minutes) : une minute correspond à 6° (360 /60) sur un cadran horaire.
Exercice
Ci-dessous document HTML avec une horloge digitale affichée dans une 'toile'
Consignes
Il doit y avoir rafraichissemnent sans rechargement de la page donc via un "timer" qui appelle une fonction
d'actualisation chaque seconde.
Pour afficher la date du jour au format francophone utilisez le constructeur Intl.DateTimeFormat.
Tous ces outils sont évoqués dans le chapitre "Objets natifs en JavaScript" du tuto sur ce langage.
Cliquez ici !
Extrait du script
let maintenant = new Date();
// heure au format francophone
let heure = maintenant.toLocaleTimeString();
...
// création d'un format de date
let format_date = new Intl.DateTimeFormat("fr-FR", {weekday : "long",
year : "numeric" , month : "long", day : "numeric"});
// format pour afficher la date en français
let cejour = format_date.format(maintenant);
...
Un jeu de squash
Si vous trouvez que le jeu est trop facile ; comment le durcir ?
Le code dans ce document
Code HTML
Le script
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
var X = canvas.width;
var Y = canvas.height;
var balle =
{
x: X/2,
y: 20,
vx: 3,
vy: 4,
rayon: 15,
dessin: function ()
{
ctx.beginPath();
ctx.arc(this.x, this.y, this.rayon, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = 'red';
ctx.fill();
// rajoutez un ombrage de la balle
},
}; // fin définition objet balle
var raquette =
{
x: X/2,
y: Y-15,
vx: 15,
w: 70,
h:10,
dessin: function ()
{
ctx.fillStyle = 'navy';
ctx.fillRect(this.x,this.y, this.w, this.h);
// rajoutez un ombrage de la raquette
},
}; // fin définition objet raquette
balle.dessin();
raquette.dessin();
canvas.onclick = function()
{
var stop = setInterval(boucle_jeu,50);
var compteur =0;
function boucle_jeu()
{
ctx.clearRect(0,0,X,Y);
compteur++;
balle.dessin();
raquette.dessin();
// changer coordonnées balle
balle.x +=balle.vx;
balle.y +=balle.vy;
// gestion des rebonds
if(balle.x > X-15 || balle.x <= 15) {balle.vx = -balle.vx;}
if (balle.y < 15) {balle.vy = -balle.vy;}
// Si balle atteint le bas
if (balle.y > Y - 15)
{
if (balle.x > raquette.x && balle.x < raquette.x + raquette.w)
{balle.vy = -balle.vy;} // balle interceptée par raquette donc rebond
else // balle non interceptée par raquette
{
alert('perdu ; nombre de points : ' + Math.round(compteur/10));
balle.x = X/2 ;balle.y = 20 ;raquette.x =X/2;
ctx.clearRect(0,0,X,Y);
balle.dessin(); raquette.dessin();
clearInterval(stop);
}
} // fin si externe
// gestion clavier
document.onkeydown = function(e)
{
if (e.keyCode == 37) {raquette.x -=raquette.vx; }
if (e.keyCode == 39) {raquette.x += raquette.vx; }
}
} // fin boucle_jeu
} // fin fonction anonyme
Puis on dessine ces deux objets dans la 'toile'.
Donc pour 'durcir' le jeu il suffit de jouer sur ce paramètre.
si un bord haut/gauche/droit est atteint alors balle.vx / balle.vy change de signe :
if(balle.x > X-15 || balle.x <= 15) {balle.vx = -balle.vx;}
if (balle.y < 15) {balle.vy = -balle.vy;}
si la raquette intercepte la balle alors alors balle.vy change de signe donc rebond de la balle.
if (balle.x > raquette.x && balle.x < raquette.x + raquette.w)
{balle.vy = -balle.vy;}
Déplacer un objet avec la souris
Il faut alors maitriser la méthode Javascript getBoundingClientRect() associée à un élément du DOM.
Les propriétés left & top appliquées à cette méthode retournent la position de l'élément du DOM dans la fenêtre.
Il faut aussi utiliser les propriété clientX & clientY qui appliquées à l'objet de type "event"
retournent respectivement les positions X & Y du pointeur dans la fenêtre.
Ci-dessous un document HTML avec un canevas
Le code du document
Code HTML
Le script
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var X = canvas.width;
var Y = canvas.height;
ctx.font="18pt Arial";
ctx.fillStyle="purple";
function info(e)
{
ctx.clearRect(0,0,X,Y); // efface le cadre
var element = canvas.getBoundingClientRect();
// calcul de la position de la souris dans le caneva
var XcurseurT = Math.round(e.clientX - element.left);
var YcurseurT = Math.round(e.clientY - element.top);
var info1 = "Position du curseur dans la fenêtre :" + e.clientX + " ," + e.clientY;
var info2 = "Position du curseur dans le canevas :" + XcurseurT + " , " + YcurseurT;
ctx.fillText(info1, 50, Y/5 *2);
ctx.fillText(info2, 50, Y/5 *4);
}
Pour calculer la position Y du pointeur dans le canevas il faut retirer de sa position Y dans la fenêtre la position 'top' du
canevas.
Contrôler une balle avec la souris
Ci-dessous un canevas dans cette page web
Actualisez la page pour mettre fin à l'animation.
Tout déplacement de la souris (après le clic) s'accompagne du déplacement de la balle rouge.
Les coordonnées de la balle sont alors affichées sous le canevas dans une boite DIV.
Le code correspondant
Sous la balise canvas un élément div.
Le script
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
var X = canvas.width;
var Y = canvas.height;
var info = document.getElementById("info");
const balle = {
x: X/2,
y: Y/2,
vx: 5,
vy: 1,
radius: 25,
color: "red",
dessin() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
},
};
balle.dessin();
canvas.addEventListener("click", function()
{
var element = canvas.getBoundingClientRect();
canvas.addEventListener("mousemove", function(e)
{
ctx.clearRect(0,0,X,Y);
var XcurseurT = Math.round(e.clientX - element.left);
var YcurseurT = Math.round(e.clientY - element.top);
info.innerHTML ="Position X & Y de la souris dans le canevas : "
+ XcurseurT + " " + YcurseurT ;
balle.x = XcurseurT;
balle.y = YcurseurT;
balle.dessin();
});
});
Notez que l'événement "mousemove" est déclenché uniquement si il y a eu un clic préable.
Pour déplacer la balle avec la souris c'est très simple : il suffit d'affecter à :
Canvas & jQuery
Connaitre la position de la souris ?
Exemple
Réduisez la fenêtre. Le code de ce document