Vous pouvez me contacter via Facebook pour questions & suggestions :
Page Facebook relative à mon site
Avec l'API Canvas on peut réaliser des animmations complexes voire des jeux.
Je présente dans ce chapitre quelques astuces pour simplifier la programmation des animations et jeux.
Autres suggestions : il est préférable de programmer objet ; rien n'interdit de combiner l'API Canvas avec la librairie jQuery.
Ci-dessous un document HTML contenant un canevas qui tient lieu de diaporama.
Toutes les deux secondes affichage d'une nouvelle photo sexy.
Cliquez sur le bouton de commmande pour mettre fin au diaporama.
La variable entier contient un entier comprend un entier compris entre 1 et 35 et 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.
Vous pouvez superposer plusieurs canevas. C'est la principe des calques.
Constatez que les 'toiles' superposées le sont entierement et sont centrées horizontalement dans la page.
Pour que les deux toiles se superposent parfaitement elles doivent être positionnées en absolu.
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 mieux que l'origine du canevas soit son centre.
: translate(X/2,Y/2).
Mais attention il faut adapter le code de la commande clearRect() en conséquence : clearRect(-X/2,-Y/2,X/2,Y/2)
Ci-dessous un document HTML contenant une 'toile' qui affiche une horloge.
L'affichage de l'heure est actualisé automatiquement.
Deux canevas superposés comme pour l'application précédente.
Je ne vous communique pas le code de la fonction qui remplit le premier canevas.
Il suffit de vous inspirer de l'application "trotteuse" ; c'est le même décor.
...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.
Intérêt de ce jeu : la programmation du clavier.
Utilisez les flèches droite et gauche du clavier pour déplacer la raquette.
Code HTML :
Il est orienté objet !
On définit deux objets : la balle et la raquette.
Puis on dessine ces deux objets dans la 'toile'.
Le jeu est déclenché en cas de clic sur le bouton de commmande.
Notez bien le test de réception de la balle par la raquette :
En clair si vous réceptionnez la balle avec les bords de la raquette vous avez quand même perdu ...
L'un des intérêts de cette application est la programmation du clavier.
Dans le cadre d'un jeu il peut être plus pratique de déplacer un objet avec la souris.
La méthode HTMLelement.getBoundingClientRect() retourne les dimensions et la position de cet élément dans la fenêtre.
Ce document affiche la position X & Y de la souris dans la fenêtre et dans le canevas.
Des animations plus complexes & jeux
Ainsi dans des scènes complexes, seuls quelques formes changent tandis que d'autres restent inchangées.
L'optimisation consiste à utiliser plusieurs calques sous forme de canevas empilés.
Un diaporama automatique
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/japonaise_nue.jpg" ; break;
case 2 : image.src ="../images/black_nue.jpg" ; break;
...
case 35 : image.src ="../images/bikini28.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 mais pas celui du dessus (qui a donc par défaut un fond
transparent).
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 "calque" du dessus je dessine et anime la "trotteuse".
Une belle horloge
Le code
Code HTML & CSS
Notez dans la partie HEAD l'instruction : meta http-equiv="Refresh" content="30"
Ce qui veut dire que toutes les trente secondes la page est rechargée ; donc la nouvelle heure est 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.
Suivez le lien
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
Ci-dessous un document HTML qui affiche le jeu de squash.
Le code dans ce document
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();
},
}; // 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);
},
}; // fin définition objet raquette
balle.dessin();
raquette.dessin();
function jeu()
{
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) || (e.keycode == 81)) {raquette.x -=raquette.vx; }
if ((e.keyCode == 39) || (e.keycode == 83)) {raquette.x += raquette.vx; }
}
} // fin boucle_jeu
} // fin fonction jeu
La boucle de jeu est itérée tous les 50 millisecondes donc 20 fois par seconde.
La raquette est déplacée latéralement par les touches de direction "gauche" et "droite".
La balle ne peut sortir du canevas : si un bord haut/gauche/droit est atteint alors balle.vx / balle.vy change de signe.
Si la balle atteint le bas et est interceptée par la raquette alors rebond sinon fin de partie.
En cas de fin de partie le score est affiché ; il est égal au nombre d'itérations de la boucle de jeu / par 10.
Donc plus le score est élevé et plus vous avez tenu longtemps.
if (balle.x > raquette.x && balle.x < raquette.x + raquette.w)
{balle.vy = -balle.vy;} // balle interceptée par raquette donc rebond
Que faire pour corriger ce défaut ?
Faites évoluer ce jeu
Afin de vérifier si vous maitriser le script vous pouvez le faire évoluer :
La programmation du clavier
document.onkeydown = function(e)
{ // si appui sur une touche
if ((e.keyCode == 37) || (e.keycode == 81)) gauche(); // déplacement à gauche raquette
if ((e.keyCode == 39) || (e.keycode == 83)) droite();
}
Déplacer un objet avec la souris
Il faut maitriser la méthode Javascript getBoundingClientRect() qui s'applique à un élément du DOM tel un canevas.
Connaitre la position de la souris dans le canevas
Ci-dessous un document HTML avec un canevas
Le code de ce document