Animations SVG avec Snap : les différentes méthodes

Dans ce troisième chapitre je vais vous montrer qu'il existe d'autres événements que click, mouseover, mouseout.
Je vais revenir aussi sur les méthodes Snap.animation() & animate() mais aussi présenter la méthode Snap.set() qui permet de définir un ensemble de formes en une seule instruction.
Je vais aussi vous montrer que l'on peut partir d'images vectorielles existantes.

Exemple 1 : des ronds qui s'animent

Le rendu

Pour animer un rond il suffit de le cliquer.
Actualisez la page pour repositionner les ronds.

Les ronds deviennent entièrement opaques, se déplacent vers la droite et grandissent. Puis un message apparait dans une boite de dialogue.

Le script

Dans ce chapitre je ne vous indique plus l'instruction HTML pour créer la zone de dessin adaptatvie puisque c'est toujours la même syntaxe.
SVG viewBox = ... width = ... height = ... ID = ...

	var s = Snap("#zone0") ;
	// dessin de deux cercles
	var rond1 = s.circle(200,200,100).attr({fill : "red", fillOpacity : .1}); 
	var rond2 = s.circle(50,50,50).attr({fill : "green", fillOpacity : .1}); 
	
	// définition d'un modèle d'animation
	var anim_modele =Snap.animation({fillOpacity : 1, transform:"t500 200 s2"}, 5000, 
			function(){alert("Actualisez la page !");} );
	
	// fonction d'animation commune à plusieurs formes
	function anime() {this.animate(anim_modele);}
	
	// animations sur clic
	rond1.click(anime); 
	rond2.click(anime);

On définit un modèle d'animation (anim_modele) avec la méthode Snap.animation().
Le modèle d'animation consiste en une opacité totale et une transformation : translation et doublement de taille.
Ici j'ai rajouté un troisième argument à la méthode : une fonction de rappel qui consiste en l'affichage d'un message.
On utilise cet objet d'animation pour définir une fonction d'animation générique puisque l'élément est désigné par le mot "this".
On applique sur clic cette fonction d'animation générique aux deux cercles.

Exemple 2 : des images qui s'animent

Le rendu

Survolez l'une des images ; elle s'agrandit et devient opaque !
L'image reprend sa transparence et sa taille initiale à la fin du survol.

Le script

ViewBox de 900 par 600.

	var s = Snap("#zone1") ;
	//insertion de deux images sexy dans le canevas SVG
	var image1 =s.image("../images/brune_nue.jpg",50,100, 450,300).attr({opacity : .1}); 
	var image2 =s.image("../images/black_nue.jpg",500,100, 300,400).attr({opacity : .1}); 
	
	// deux modèles d'animation
	var action1 = Snap.animation({opacity : 1 , transform :'s2' },2000); 
	// opacité totale & doublement taille
	var action2 = Snap.animation({opacity : .1, transform :'s0.5' },2000); 
	// quasi transparence et taille divisée par 2
	
	// fonctions d'animation communes à plusieurs formes
	function faction1() {this.animate(action1); }
	function faction2() {this.animate(action2); }

	// application des fonctions aux images sur événements
	image1.mouseover(faction1); image1.mouseout(faction2); 
	image2.mouseover(faction1); image2.mouseout(faction2); 

On insère deux images matricielles dans le canevas via la méthode image(). Ce qui est logique puisqu'en SVG traditionnel la balise d'insertion d'images existantes est image.
On définit ensuite deux modèles d'animation : action1 & action2
On définit deux fonctions génériques (élément = "this") à partir des deux modèles d'animation : faction1 & faction2
Les fonctions génériques sont appliquées aux deux images ET sur deux évènements : mouseover & mouseout.

Le script simplifié

On pourrait simplifier les deux dernières lignes de code !

	// application des fonctions aux images sur événement hover
	image1.hover(faction1,faction2);  
	image2.hover(faction1,faction2); 

Emploi de la méthode hover() qui remplace avantageusement les méthodes mouseover & mouseout
Syntaxe de cette méthode : élément.hover(fonction1, fonction2).
"fonction1" est déclenchée lors du survol ; "fonction2" est déclenchée dès que le pointeur quitte l'élément.

Les utilisateurs de jQuery ne seront pas surpris par cet événement puisqu'il existe dans ce fameux framework.

Utiliser des fichiers vectoriels existants

Vous pouvez insérer des images existantes dans le canevas via le CSS (propriété background) ou via la méthode image de Snap et ces images peuvent être des images vectorielles ...
Dans l'exemple ci-dessous j'insère deux fichers SVG produits avec Inkscape.
L'une (piste.svg) doit occuper tout le canevas et est donc insérée via la propriété CSS background et l'autre (avion.svg) est un "sprite" et doit être insérée via la méthode image() de la libraire snap svg.

Le code correspondant

HTML & CSS :

<svg viewBox ="0 0 900 600" width ="80%" height ="auto" id ="zone3" style ="background : url(piste.svg) ; background-size :cover;"> <!--Décor de l'animation une image vectorielle--> </svg> <p>L'image "piste.svg" ne fait que 2 KO suite à l'optimisation.

Le script

ViewBox de 900 par 600.

	var s = Snap("#zone3");
	//insertion d'une image SVG dans le canevas
	var avion = s.image("avion.svg", 0,0, 52,22 );
	// insertion d'une image vectorielle en guise de sprite
	var flou = s.filter(Snap.filter.blur(10,10));
	var soleil =s.circle(850,50,40).attr({fill : "yellow", filter : flou}); 
	//rajout du soleil dans le décor
	var ombrage = s.filter(Snap.filter.shadow(-5,5, .5));
	// définition d'un filtre SVG : ombrage
	avion.attr({filter : ombrage}); 
	//application de l'ombrage au sprite
	
	var anim_modele3 =Snap.animation({transform:"t400 500 s5"}, 12000);
	function deplace() {avion.animate(anim_modele3);}
	avion.click(deplace); 

Le script ne présente aucune difficulté.
L'image "avion.svg" ne pèse que 1 KO suite à son optimisation avec SVG Editor.
J'en profite pour faire une "piqûre de rappel" sur les filtres. Il manque en effet un soleil dans le décor ; donc je rajoute un rond jaune flouté. Je rajoute aussi une ombre à l'avion.

Le modèle d'animation est référencé par la variable anim_modele2 car dans un script précédent (mais dans la même page) il y avait déjà emploi de la variable anim_modele ...

Le rendu

Cliquez sur le jet pour démarrer l'animation.
Actualisez la page pour repositionner l'avion.

Du bon usage de "this"

Exemple

Cliquez sur l'un des carrés ; il disparait à la fin de l'animation.

Actualisez la page pour afficher de nouveau les carrés.

Le script

Viewbox de 900 par 600.

	var s = Snap("#zone5") ;
	function fsuite() {this.remove();} // effacement objet courant
	
	// définition d'un modèle d'animation
		var anim_modele5 =Snap.animation({fillOpacity : 1, transform :"t800 200 r45 s1.5"}, 10000, fsuite);
	// modèle d'animation avec fonction de rappel : fsuite
	
	function anime5() {this.animate(anim_modele5);}
	// fonction d'animation générique basée sur le modèle d'animation
	
	var carre1 = s.rect(0,0,100,100).attr({fill : "red", fillOpacity : .1}); 
	var carre2 = s.rect(0,100,150,150).attr({fill : "green", fillOpacity : .1}); 
	
	// animations sur clic
	carre1.click(anime5); 
	carre2.click(anime5);

Je vous montre ici que le troisième argument de Snap.animation() peut être une fonction nommée et que dans cette fonction nommée (ici "fsuite") on peut utiliser le mot "this". Il s'agit donc d'une fonction générique (porte sur l'élément courant) !

La méthode Snap.set()

Encore une méthode d'animation !
"Set" veut dire ensemble. On peut définir un ensemble de formes, le nommer et appliquer à cet ensemble une animation complexe comprenant autant de parties que d'éléments dans le set.

Exemple 1

Cliquez sur le premier rond pour démarrer l'animation.
Actualisez la page pour revenir à la situation initiale.

Les ronds grandissent, deviennent opaques et changent de couleur sauf le quatrième qui n'est pas concerné par l'animation

Le script

ViewBox de 900 par 600.

function fanimation()
{
	var paper = Snap("#zone6"); 
	var ombrage = paper.filter(Snap.filter.shadow(10, 10, .5));
	var rond1 = paper.circle(30, 30,20);
    serie = Snap.set(rond1, paper.circle(100, 100, 30),paper.circle(200,200,40), paper.circle(300,300,50));
	var param = {fill : "red", fillOpacity : .2, filter : ombrage};
	serie.attr(param); 
	function fanimer()
	{
		serie.animate(
		[{r: 30,fillOpacity :.5, fill : "black"}, 3000], 
		[{r: 50,fillOpacity :.8, fill : "orange"}, 4000], 
		[{r: 60,fillOpacity :1, fill:"green"}, 5000]
		);
	}
	
rond1.click(fanimer); 
}
fanimation();	//appel de la fonction d'animation

Commentaire

Le script comprend désormais une fonction (fanimation) et l'appel de cette fonction. Ainsi nous sommes certains que les variables définies seront locales. Ainsi le risque d'ambiguité avec d'autres variables définies dans d'autres scripts de la même page est levé.

Grâce à la notion de "set" (ensemble) on peut en quelques lignes de code seulement styler et animer plusieurs objets !
Notez bien la syntaxe de "serie.animate". Il y a en effet la description de trois animations ; chaque animation est entre crochets !
La première animation s'applique au premier élément de "serie" (rayon de 20) ; la deuxième animation s'applique au deuxième élément (le cercle de rayon 30). Il n'y a que trois animations alors que l'ensemble "serie" comprend quatre éléments. Donc le dernier rond (rayon de 50) n'est pas animé.

Donc l'un des avantages de la méthode est qu'il n'est pas nécessaire de nommer les différentes formes ; c'est l'ordre des formes qui compte.

Autre exemple sur Snap.set()

Rien n'interdit de combiner dans un même script deux méthodes puissantes : Snap.set() et Snap.animation()

Cliquez sur le premier rond pour démarrer l'animation.

Les trois premiers ronds se déplacent vers la droite et le bas tout en passant au violet et en doublant de taille.

Le script

ViewBox de 900 par 600.

function fanimation2()
{
	var paper = Snap("#zone7"); 
	var ombrage = paper.filter(Snap.filter.shadow(10, 10, .5));
	var rond2 = paper.circle(30, 30,20);
    serie2 = Snap.set(rond2, paper.circle(100, 100, 30),paper.circle(200,200,40), paper.circle(300,300,50));
	var param = {fill : "red", fillOpacity : .2, filter : ombrage};
	serie2.attr(param); 
	var anime_modele = Snap.animation({fillOpacity : 1 , transform :'s2 t400 200', fill : "purple" },5000); 
	function fanimer2()
	{
		serie2.animate(
		[anime_modele], 
		[anime_modele], 
		[anime_modele]
		);
	}
rond2.click(fanimer2); 
}
fanimation2();	//appel de la fonction d'animation

Commentaire

Je crée une série d'éléments nommée "serie2".
Je définis un modèle d'animation dans la variable anime_modele qui prévoit : opacité totale, transformation, passage au violet.
J'argumente serie2.animate avec ce modèle d'animation.

Chapitre suivant : le rythme de l'animation
Retour menu