Accueil

Dessiner avec SVG - sommaire

Vous pouvez me contacter via Facebook (questions, critiques constructives) : page Facebook relative à mon site

Animer un canevas SVG avec Javascript

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 ...

Avec JavasScript de base

Le code SVG

<svg width="50%" height="auto" viewBox ="0 0 400 400" style = 'background : yellow; ' > <circle cx="200" cy="200" r="10" style =" fill : red ; fill-opacity : 0.1;" /> </svg>

Pour que l'image vectorielle s'adapte à tous les écrans (image adaptative), la largeur du canevas SVG est exprimée en pourcentage. Les positions et dimensions des formes seront calculées grâce aux valeurs de l'attribut viewBox.
Rappel : notion cruciale de viewBox est présentée dans le tuto "Dessiner avec SVG" dans le même site.

Le script

	var X = 400 ; //largeur définie dans le viewbox
	var rond = document.querySelector('circle') ; 
	var rayon = rond.getAttribute('r'); 
	var opacite =rond.style.fillOpacity ;
	rayon = parseInt(rayon) ; opacite =parseFloat(opacite);
	var v_rayon = 2; var v_opacite = 0.01 ;
	setInterval(animate,100) ; 
	function animate() 
	{
		if (rayon == X/2) { 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

Si le script est interne à la page, il doit être compris dans la balise SCRIPT.

Si vous savez modifier le DOM HTML via JavaScript vous ne serez pas surpris par le code du script.
Ici il faut modifier la valeur de la propriété opacity) et celle de l' attribut R pour l'élément SVG de type circle.

Il est difficile dans le cadre d'un script de récupérer une des valeurs de l'attribut viewBox de la balise SVG. Donc je me contente d'écrire l'instruction : var X = 400 (largeur définie dans le viewBox). Donc si vous décidez de modifier les valeurs de l'attribut viewBox il faudra corriger cette instruction du script.

Continuons l'examen du script !

rond est une variable objet qui référence le premier élément de type "circle" puisque j'utiliser querySelector().
var rayon = rond.getAttribute('r') : cette instruction permet de récupérer la valeur de l'attribut r de l'élément "rond".
Mais attention la valeur primitive de la variable rayon est la chaine "10" (et non pas l'entier 10). Et comme en JavaScript "10" + 2 donne 102 (Il y a en effet concaténation puisque l'un des termes est une chaine). Il faut donc avant toute tentative d'incrémentation de la variable rayon convertir cette dernière en un entier avec la fonction parseInt.

var opacite =rond.style.fillOpacity : la variable opacité récupère la valeur de la propriété de style fill-opacity. Mais dans un script il faut écrire fillOpacity (syntaxe JavaScript).
La variable opacite récupère une chaine. Il faut donc la convertir sous forme d'un décimal avec la fonction parseFloat.

C'est la fonction JS animate qui modifie le rayon du cercle et son opacité.
Cette fonction est appelée tous les 100 millisecondes donc 10 fois par seconde grâce à 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 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/2 et au minimum de 10.
La variable v_opacite 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.

Avec jQuery

Rien n'interdit d'animer des éléments SVG en JS-jQuery.
Reprenons le même thème cette fois un script écrit en jQuery.

Le code HTML et SVG

... <script src ="jquery.js"></script> ... </head><body> ... <svg width="50%" height="auto" viewBox ="0 0 400 400" style = 'background : yellow; ' > <circle cx="200" cy="200" r="10" style =" fill : red ; fill-opacity : 0.1;" /> </svg>

Il faut bien sûr dans la partie HEAD charger la librairie jQuery avec un script. J'ai bien sûr supposé que le fichier .js est dans le même dossier que la page.

Le code SVG est strictement identique à la version précédente.
Notez bien que le rayon est passé en attribut et l'opacité est passée en propriété CSS !

Le script

	var rond2 = $('circle:last') ; 
	var X = 400 ;
	var rayon2 = rond2.attr('r'); 
	var opacite2 =rond2.css('fillOpacity') ;
	rayon2 = parseInt(rayon2) ; opacite2 =parseFloat(opacite2);
	var v_rayon = 2; var v_opacite = 0.01 ;
	setInterval(animate2,100) ; 
	function animate2() 
	{
		if (rayon2 == X/2) { v_rayon = -2 ;v_opacite = -0.01; }
		if (rayon2 == 10) { v_rayon = 2 ; v_opacite = 0.01;  }
		rayon2 += v_rayon ; 
		opacite2 += v_opacite; 
		rond2.attr('r',rayon2) ; 
		rond2.css('fillOpacity', opacite2); 
	} // fin fonction animate

On doit référencer le dernier élément "circle" de la page.
Pour récupérer / modifier la valeur d'un attribut il faut utiliser la méthode attr().
Pour récupérer /modifier la valeur d'une propriété CSS il faut utiliser la méthode css().

On ne peut pas dire que le script soit vraiment plus succinct qu'en JS de base mais la syntaxe est beaucoup plus simple : mêmes méthodes pour récupérer OU modifier les attributs et propriétés ; ce qui n'est pas le cas en JS de base (des méthodes SET et des méthodes GET). Autre différence notable avec JS de base : le ciblage des noeuds du DOM.

Déplacements de "sprites"

On désigne par "sprites" les personnages d'une animation qui se déplacent. Il s'agit souvent de GIF animés.

Ici on se contente d'intégrer deux gif animés avec la balise image puis on les déplace avec JavaScript.
Par contre le décor est réalisé via le CSS ("background" du canevas SVG rempli d'un dégradé linéaire) et avec le SVG : clonage de deux objets SVG identifiés "bosquet" et "muret". le décor intégration d'un gif animé

Le code SVG correspondant

<svg viewBox ="0 0 900 60" width="100%" height="auto" style = "background : linear-gradient( 45deg, skyblue, white )" > <defs> <g id ='bosquet'> <rect x = '16' y = '30' width = '8' height = '20' fill = "maroon" /> <ellipse cx="20" cy="20" rx="15" ry="20" fill="green" /> </g> <g id = 'muret'> <rect x = '0' y = '20' width = '50' height = '30' fill = 'rgb(255,255,170)' /> <rect x = '20' y = '30' width = '4' height = '2' fill = 'rgb(255,0,0)' /> <rect x = '10' y = '40' width = '4' height = '2' fill = 'rgb(255,0,0)' /> <rect x = '30' y = '45' width = '4'height = '2' fill = 'rgb(255,0,0)' /> </g> </defs> <desc>le décor </desc> <use xlink:href="#muret" x="0" y="0" /> <use xlink:href="#muret" x="50" y="0" /> <use xlink:href="#bosquet" x="100" y="0" /> <use xlink:href="#bosquet" x="150" y="0" /> <use xlink:href="#bosquet" x="200" y="0" /> <use xlink:href="#muret" x="250" y="0" /> <use xlink:href="#bosquet" x="300" y="0" /> <use xlink:href="#muret" x="350" y="0" /> <use xlink:href="#muret" x="400" y="0" /> <use xlink:href="#muret" x="450" y="0" /> <use xlink:href="#bosquet" x="500" y="0" /> <use xlink:href="#bosquet" x="550" y="0" /> <use xlink:href="#bosquet" x="600" y="0" /> <use xlink:href="#muret" x="650" y="0" /> <use xlink:href="#bosquet" x="700" y="0" /> <use xlink:href="#muret" x="750" y="0" /> <use xlink:href="#bosquet" x="800" y="0" /> <use xlink:href="#muret" x="850" y="0" /> <desc>intégration d'un gif animé</desc> <image x ="10" y="10" width="90" height="40" xlink:href="../images/chien.gif" id ='chien'/> <image x ="100" y="10" width="90" height="40" xlink:href="../images/chat.gif" id ='chat'/> </svg>

Une règle de style en ligne dans la balise SVG afin que le canevas ait un fond dégradé (bleu ciel vers blanc).

Le script correspondant

	var chien = document.querySelector('#chien'); // variables objet
	var chat = document.querySelector('#chat');
	var X = 900; // X récupère la largeur du viewBox
	var x_chien = 10 ;
	var x_chat = 110; 
	setInterval(animate,50) ; // fonction animate exécutée 20 fois par seconde
	function animate() 
	{ 	
		x_chien = x_chien + 2 ; 	
		if(x_chien >= X)  x_chien = -90 ; x_chat = x_chien + 100 ; 		
		chien.setAttribute('x', x_chien); 
		chat.setAttribute('x', x_chat); 
	}

Le code JS est très simple. Dans le cadre d'une fonction animate (qui est exécutée 20 fois par seconde) on se contente de changer la valeur de l'attribut x des objets SVG chien et chat

Créer de nouveaux éléments SVG dans le canevas

L'insertion de nouveaux éléments HTML dans une page via JavaScript est facile (voir tuto "JavaScript & jQuery").
L'insertion de nouveaux noeud SVG est un peu plus délicate. C'est ce que nous allons traiter dans cette page.

Cette animation SVG pourrait s'appeler "coucher de soleil".
Le soleil descend lentement ; le ciel s'assombrit lentement pour devenir noir ; les étoiles apparaissent.

Pour relancer l'animation actualisez la page !

Le code SVG

<svg width="100%" height="auto" viewBox ="0 0 800 400" xmlns="http://www.w3.org/2000/svg"> <defs> <filter id="flou"> <feGaussianBlur stdDeviation="12" /> </filter> </defs> <rect x="0" y="0" height="400" width="800" fill="black"/> <rect x="0" y="0" height="400" width="800" fill="blue" id ="ciel" /> <circle id="soleil" cx="400" cy="250" r="75" fill="orange" filter = 'url(#flou)'/> ...

Un flou est défini et s'applique à un cercle orange identifié "soleil".
Deux rectangles occupant toute la zone de dessin : un rempli de noir et un autre au dessus rempli de bleu et identifié "ciel".
Le cercle orange et flouté (soleil) est dessiné au dessus.

Le script

	var compteur = 0 ;
	function coucher_soleil() 
	{
	soleil = document.getElementById("soleil"); 
	soleil.setAttribute("cy", 250+(compteur*2.3));    
	// soleil descend doucment
 
	ciel = document.getElementById("ciel");
	ciel.setAttribute("opacity", (100-compteur)/100); 
	// fond bleu devient doucement transparent donc ciel devient noir
	etoile = document.createElementNS("http://www.w3.org/2000/svg", "circle");
	etoile.setAttribute("fill", "yellow");
	etoile.setAttribute("cx", Math.random()*800);
	etoile.setAttribute("cy", Math.random()*400);
	etoile.setAttribute("r", 2);
 	scene = ciel.parentNode;
	scene.insertBefore(etoile,ciel);
	compteur++;
	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 100 fois.
Notez qu'elle s'appelle elle-même. Donc pour que démarre l'animation il faut surtout un appel de cette fonction : coucher_soleil();

Syntaxe

Si vous avez visité le tutoriel "javaScript & jQuery"(page "manipuler le DOM) dans le même site vous savez qu'il est possible avec JS de créer de nouveaux éléments HTML en utilisant les méthodes createElement() et appendChild.

Pour créer et insérer un élément SVG c'est un peu plus compliqué. Il faut utiliser la méthode createElementNS pour préciser l'espace de nommage. Il faut en effet préciser qu'il ne s'agit pas d'un nouvel élément HTML mais d'un nouvel noeud SVG !!!
Ensuite pour insérer le nouvel élément SVG dans le DOM XML on doit utiliser La méthode insertBefore qui est moins intuitive que appendChild