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 aussi vous présenter les modèles d'animation avec la méthode Snap.animation()
Je vais aussi vous présenter la méthode Snap.set().

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 dans la variable 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 quatre dernières instructions ; remplacer par deux.

	// 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 :

Le script

Le viewbox dans l'instruction HTML définit un repère 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

Le viewbox dans l'instruction HTML définit un repère 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()

Cette méthode permet de définir très rapidement un ensemble de formes.
Elle va de pair avec la méthode animate() mais avec cette fois une syntaxe particulière ...
"Set" veut dire ensemble. On peut définir un ensemble de formes

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

Le viewbox dans l'instruction HTML définit un repère de 900 par 600.

function fzone6()
{
	var paper = Snap("#zone6"); 
	var ombrage = paper.filter(Snap.filter.shadow(10, 10, .5));
	var rond1 = paper.circle(30, 30,20);
    ensemble = 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};
	ensemble.attr(param); 
	function fanimer()
	{
		ensemble.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); 
rond1.click(fanimer); 
}
fzone6();	//appel de la fonction qui remplit et anime la zone6

Commentaire

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

Le gros avantage de la méthode Snap.set() est qu'elle permet de définir et styler de nombreux éléments sans devoir les nommer.

Animation1 s'applique au premier élément de "ensemble" ; Animation2 s'applique au deuxième élément ; animation3 s'applique au troisième élément.
Il n'y a que trois animations alors que l'ensemble "serie" comprend quatre éléments. Donc le dernier rond n'est pas animé.

Autre exemple sur Snap.set() et animate() avec une syntaxe particulière

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 quatre ronds se déplacent vers la droite et le bas tout en passant au violet et en doublant de taille.

Le script

function fzone7()
{
	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],
		[anime_modele]
		);
	}
rond2.click(fanimer2); 
}
fzone7();	//appel de la fonction qui s'applique à la zone7

Commentaire

Je crée un ensemble d'éléments nommé "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 quatre fois.
Notez bien que je n'ai pas eu à nommer trois des quatre ronds ...

Dans le chapitre suivant : le rythme de l'animation
Retour menu