Símbolos animados (2)

facebook-svg gplus-svg twitter-svg

Esta es una continuación de Símbolos animados (1)

Animando múltiples imágenes SVG

Es normal que queramos utilizar el símbolo SVG ( creado anteriormente ) varias veces en la misma página, y claro está, animarlo también.

¿Como hacerlo?

Primero el script atraviesa todo el documento en búsqueda de elementos <use>.

var useElmts = document.getElementsByTagName("use");

A continuación escribiremos un bucle for que recorre el array de los elementos <use>.

for(var i=0; i<useElmts.length; i++){. . . 

Dentro del bucle hay una función anónima. Se trata de una función anónima encapsulada que tiene esta sintaxis:

(function(){
      alert(2 + 2);
})();

Las funciónes anónimas encapsuladas se auto ejecutan de inmediato. Lo que escribimos arriba es equivalente a:

// construye la función
function DosMasDos(){
      alert(2 + 2);
}
// llama la función
DosMasDos(); 
  

Lea más sobre las funciones anónimas encapsuladas en JavaScript: Explain JavaScript's encapsulated anonymous function syntax

El contenido de esta función anónima es muy parecido a lo que hemos visto anteriormente. A continuación hemos marcado con //----- el principio y el fin de la función anónima.

  • var useElmts = document.getElementsByTagName("use");
  • for(var i=0; i<useElmts.length; i++){
  • (function () { //---------------------------------------------------
  • var elId = useElmts[i].id;
  • var use = document.getElementById(elId);
  • // calcula el valor del centro de rotacion
  • var valAttr = new Array();
  • var attrRy = new Array("x", "width", "y", "height");
  • for( var j = 0;j<attrRy.length; j++){
  •    if(use.hasAttribute(attrRy[j])){
  •       valAttr[j] = Number(use.getAttribute(attrRy[j]));
  •       }else{
  •       valAttr[j] = 0;}   
  •    }
  • var cx = valAttr[0] + valAttr[1]/2;
  • var cy = valAttr[2] + valAttr[3]/2;
  • // establece el valor del atributo transform de use
  • use.setAttribute("transform","rotate(0 "+cx+" "+cy+")");
  • // al hacer clic en el use ( el triangulo )
  • use.addEventListener("click", function(){
  • var animId = use.getElementsByTagName("animateTransform")[0].id; //transformacion1, transformacion2 ...
  • var anim = document.getElementById(animId); //document.getElementById("transformacion1");
  • var from = anim.getAttribute("from");
  •    if(from =="0 "+cx+" "+cy){
  •    anim.setAttribute("from", "90 "+cx+" "+cy);
  •    anim.setAttribute("to", "0 "+cx+" "+cy);
  •    }else{
  •    anim.setAttribute("from", "0 "+cx+" "+cy);
  •    anim.setAttribute("to", "90 "+cx+" "+cy);
  •    }
  • }, false);
  • }()); //--------------------------------------------------------------
  • }

En el HTML tenemos 4 lienzos SVG. Primer lienzo es donde guardamos las definiciones <defs>, en este caso el #triangulo. Este lienzo tiene display:none.

Los otros tres lienzos son aquellos donde utilizamos el #triangulo con <use>. Sabemos que el elemento <symbol> soporta el atributo viewBox, y por tanto una vez dibujado un símbolo podemos generar replicas de dimensiones variables. Solo hay que cambiar el valor de la anchura width y de la altura height del elemento <use>.
Los elementos <use> que muestran el #triangulo tienen asignadas diferentes valores para la anchura width, la altura height y para las coordenadas x e y, y por tanto generan copias de tamaño diferente.

Los elementos <use> tienen asignado un id: "use" seguido de un número, por ejemplo id="use1".
También las animaciones <animateTransform> tienen asignado un id: "transformacion" seguido de un número, por ejemplo id ="transformacion1".
Esto es muy útil a la hora de manipular los elementos a través de un bucle for.

  • <svg width= "250" height= "250" viewBox= "0 0 250 250" style= "display :none;">
  • <defs>
  • <symbol id= "triangulo" viewBox= "0 0 250 250" >
  • <polygon points= "200,125 87.5,190 87.5,60.0 200,125" style= "fill :#f00;" />
  • </symbol>
  • </defs>
  • </svg>
  • <!---->
  • <svg width= "150" height= "150" viewBox= "0 0 150 150">
  • <g>
  • <use id= "use1" xlink:href= "#triangulo" x= "50" y= "50" width= "50" height= "50" transform= "">
  • <animateTransform id= "transformacion1"
  • attributeName= "transform"
  • attributeType= "XML"
  • type= "rotate"
  • from= "" to= ""
  • begin= "use1.click"
  • dur= "500ms"
  • fill= "freeze"/>
  • </use>
  • </g>
  • </svg>
  • <!---->
  • <svg width= "150" height= "150" viewBox= "0 0 150 150">
  • <g>
  • <use id= "use2" xlink:href= "#triangulo" x= "60" y= "60" width= "30" height= "30" transform= "">
  • <animateTransform id= "transformacion2"
  • attributeName= "transform"
  • attributeType= "XML"
  • type= "rotate"
  • from= "" to= ""
  • begin= "use2.click"
  • dur= "500ms"
  • fill= "freeze"/>
  • </use>
  • </g>
  • </svg>
  • <!---->
  • <svg width= "150" height= "150" viewBox= "0 0 150 150">
  • <g>
  • <use id= "use3" xlink:href= "#triangulo" x= "25" y= "25" width= "100" height= "100" transform= "">
  • <animateTransform id= "transformacion3"
  • attributeName= "transform"
  • attributeType= "XML"
  • type= "rotate"
  • from= "" to= ""
  • begin= "use3.click"
  • dur= "500ms"
  • fill= "freeze"/>
  • </use>
  • </g>
  • </svg>

A continuación queremos crear un botón utilizando símbolos SVG animados