Vous pouvez me contacter via Facebook pour questions & suggestions :
Page Facebook relative à mon site
Jusqu'à présent nous avons animé les éléments SVG via le SMIL. Mais il existe deux autres solutions : animer avec JS ou
animer avec CSS.
Dans ce chapitre j'évoque l'animation d'objets SVG via un script JS.
Le recours à JS est parfois inévitable comme je le montre pour l'horloge analogique en fin de chapitre.
Commençons par une animation basique : le rond rouge est de plus en grand et de plus opaque puis c'est l'inverse et le cycle reprend à l'infini ...
Ce code JS est bien sûr balisé par le conteneur SCRIPT si il est interne.
var X = 400 ; //largeur définie dans le viewbox
var rond = document.querySelector('circle') ;
var rayon = rond.getAttribute('r');
rayon = parseInt(rayon) ;
var opacite =rond.style.fillOpacity ;
opacite =parseFloat(opacite);
var v_rayon = 2; var v_opacite = 0.01 ;
setInterval(animate,100) ;
function animate()
{
if (rayon >= X/4) { v_rayon = -2 ;v_opacite = -0.01; }
if (rayon <= 10) { v_rayon = 2 ; v_opacite = 0.01; }
rayon += v_rayon ;
opacite += v_opacite;
rond.setAttribute('r',rayon) ;
rond.style.fillOpacity = opacite ;
} // fin fonction animate
Ici il faut modifier la valeur de la propriété fill-opacity et la valeur de l'attribut r de l'objet
de type "circle".
var rayon = rond.getAttribute('r') : récupère la valeur de l'attribut r de l'objet référencé "rond".
La méthode getAttribute() retourne une chaine numérique ; il faut donc convertir en entier avant
toute incrémentation.
var opacite =rond.style.fillOpacity : la variable opacité récupère la valeur de la
propriété fill-opacity.
En JS il faut écrire fillOpacity (syntaxe JavaScript).
La variable opacite récupère une chaine ; il faut donc la convertir en décimal.
La fonction animate modifie le rayon du cercle et son opacité.
Cette fonction est appelée tous les 100 millisecondes donc 10 fois par seconde grâce au timer setInterval().
Étudions maintenant de plus près la fonction animate !
Pour changer la valeur d'un attribut il faut utiliser la syntaxe : élément.setAttribute("attribut",nouvelle valeur).
Pour changer la valeur d'une propriété de style il faut utiliser la syntaxe : élément.style.propriété = nouvelle valeur.
La variable v_rayon (variation du rayon) est tantôt égale à 2 et tantôt égale à -2.
Donc l'instruction rayon += v_rayon incrémente ou décrémente la variable rayon.
La valeur de rayon est au maximum de X/4 et au minimum de 10.
La variable v_opacite (variation de l'opacité) est tantôt égale à 0.01 et tantôt égale à -0.01.
Donc l'instruction opacite += v_opacite incrémente ou décrémente la variable opacite.
Il s'agit d'une préparation aux jeux vidéos en SVG-JS.
Cliquez sur le lien ci-dessous pour afficher le document (dans un nouvel onglet).
Un billard avec une boule à déplacer
Le code du canevas SVG ne pose aucune difficulté.
var billard = document.querySelector('#billard');
var boule = document.querySelector('#boule');
// programmation des touches de direction
document.onkeydown = function(event)
{
if (event.keyCode == 37) gauche();
if (event.keyCode == 39) droite() ;
if (event.keyCode == 38) haut();
if (event.keyCode == 40) bas() ;
}
// quatre fonctions de déplacement
function gauche()
{var x = boule.getAttribute('cx');
console.log(typeof x);
x= parseInt(x) ;
x-=20;
boule.setAttribute('cx',x); }
function droite()
...
function haut()
{var y = boule.getAttribute('cy');
console.log(typeof y);
x= parseInt(y) ;
y-=20;
boule.setAttribute('cy',y); }
function bas()
...
La méthode getAttribute() retourne une chaine comme l'indique la console JS. Donc pensez
à convertir avant toute incrémentation ...
Ici la boule peut sortir du billard mais il suffirait de rajouter un test dans chaque fonction pour
éviter cet inconvénient ...
Si vous avez des difficultés à comprendre la programmation du clavier en JS :
Gestion des évènements par JS
L'insertion de nouveaux éléments HTML dans une page web via JavaScript est facile.
L'insertion de nouveaux objets SVG dans un canevas est un peu plus délicate ...
Notez l'utilisation d'un filtre CSS (via la classe "flou1") pour flouter un rond orangé (le soleil).
Deux rectangles occupant toute le canevas : un rempli de noir et un autre au dessus rempli de bleu. Donc
au départ le fond du canevas est bleu.
Le cercle orange flouté (le soleil) est dessiné au dessus.
var compteur = 0 ;
var svg = document.querySelector('svg');
var noir = document.getElementById("noir");
var bleu = document.getElementById("bleu");
var soleil = document.getElementById("soleil");
function coucher_soleil()
{
// soleil descend doucement
soleil.setAttribute("cy", 250+(compteur*2));
// fond bleu devient progresssivement transparent donc le ciel devient noir
bleu.setAttribute("opacity", (100-compteur)/100);
// création d'un nouvel élément SVG
etoile = document.createElementNS("http://www.w3.org/2000/svg", "circle");
etoile.setAttribute("fill", "orange");
etoile.setAttribute("cx", Math.random()*800);
etoile.setAttribute("cy", Math.random()*400);
etoile.setAttribute("r", 2);
//insertion de cet élément dans le canevas
svg.appendChild(etoile);
compteur++;
// appel récursif de la fonction
if (compteur<= 100) setTimeout(coucher_soleil, 200);
} // fin fonction
coucher_soleil(); //démarrer animation
La fonction "coucher_soleil" est exécutée toutes les 200 millisecondes et seulement 100 fois. Donc l'animation a une durée limitée.
Notez qu'elle s'appelle elle-même (récursivité).
document.createElementNS("http://www.w3.org/2000/svg", "circle") : pour créer un nouvel objet SVG, il faut utiliser la méthode createElementNS ; dans cette méthode, il faut préciser l'espace de nommage ("http://www.w3.org/2000/svg") et le type de forme crée.
Dans le chapitre 13 (SMIL - balise animateTransform) je vous ai présenté une superbe horloge analogique.
Animation réalisée en SMIL et plus précisément avec la balise animateTransform.
Mais gros problème lorque ce document SVG est ouvert, il affiche 0H 0mn 0s ...
Ci-dessous une horloge analogique qui affiche l'heure exacte (Heures et minutes).
Il n'y a pas en effet de trotteuse.
L'intérêt pédagogique est que cette animation fait appel non seulement au SMIL mais aussi au JavaScript.
Un script JS est indispensable.
Pour le code SVG revoyez le chapitre 13 : SMIL - animateTransform
Rajout : il faut identifier les balises animateTransform.
Il a pour objectif de modifier les valeurs des attributs from des éléments animateTransform.
function horloge()
{
var anime1 = document.getElementById('anime1')
var anime2 = document.getElementById('anime2')
// instant présent
var aujourdhui = new Date();
var heure24 = parseInt(aujourdhui.getHours());
if (heure24 > 12) heure12 = heure24 -12;
else heure12 =heure24;
var minutes60 = parseInt(aujourdhui.getMinutes());
var minutesfraction = minutes60/60;
var heurefraction = heure12 + minutesfraction;
console.log("heure24 : ", heure24) ;
console.log("heure12 :", heure12) ;
console.log("minutes : ", minutes60) ;
console.log("minutes en fraction : ", minutesfraction);
console.log("instant en fraction : ", heurefraction);
var heurerayon = heurefraction * 30 ;
minutesrayon = minutes60 * 6 ;
console.log("rayon pour aiguille heure :", heurerayon);
console.log("rayon pour aiguille minutes :" ,minutesrayon);
anime1.setAttribute('from',heurerayon);
anime2.setAttribute('from',minutesrayon);
}
horloge();
setInterval(horloge,60000);
Ce script contient de nombreux affichages dans la console (instructions provisoires).
Elles sont utiles pour comprendre ma démarche.
La difficulté est que le constructeur new Date() retourne l'instant présent au format 24H et qu'une horloge
analogique est au format 12H.
Il faut ensuite convertir chaque composante (heure12, minutes60) en rayon de rotation.
heure24 : 18 heure12 : 6 minutes : 14 minutes en fraction : 0.23333333333333334 instant en fraction : 6.233333333333333 rayon pour aiguille heure : 187 rayon pour aiguille minutes : 84
heure24 : 9 heure12 : 9 minutes : 35 minutes en fraction : 0.5833333333333334 instant en fraction : 9.583333333333334 rayon pour aiguille heure : 287.5 rayon pour aiguille minutes : 210
On obtient bien le rayon de départ pour chaque aiguille.
var anime1 = document.getElementById('anime1') : la variable "anime1" identifie l'animation sur l'aiguille des heures.
anime1.setAttribute('from',heurerayon) : Je remplace la valeur de l'attribut from de la balise
animateTransform identifiée "anime1". Je rappelle que la valeur initiale de cet attribut est fixée à zéro par le SMIL.
horloge() : appel de la fonction horloge() au chargement du document
setInterval(horloge,60000) : la fonction horloge()est ensuite appelée toutes les 60 secondes.
Seriez-vous capable d'améliorer cette horloge analogique, lui rajouter une trotteuse ?
Ce que vous devez obtenir :
La fonction horloge() doit alors être appelée chaque seconde.