Gráficos circulares (4)

facebook-svg gplus-svg twitter-svg

Ir a Gráficos circulares (3)

Cuando miramos el gráfico es obvio que la "vitamina A" es mucho más abundante que la "vitamina C", ¿pero que porcentaje ocupa?. Queremos que el porcentaje aparezca en cada "gajo", justo en el medio.
Pero antes tenemos que modificar un poco la función coords.

La función coords

Hasta ahora la función coords tomaba un solo argumento: el ángulo ( a ), ya que el radio r es una variable de alcance global y no necesitamos utilizarla como argumento. Pero para la función nuevaEtiqueta, que vamos a escribir a continuación, necesitamos poder calcular las coordenadas de un punto en la circunferencia de un circulo con un radio más pequeño. Por tanto modificamos la función coords para poder utilizar como radio una variable de alcance local.

Lea más sobre el alcance o el ámbito de las variables en JavaScript.

En consecuencia la función coords toma ahora dos argumentos: el ángulo ( a ) y el radio. El segundo argumento ( radio ) es opcional : si no está declarado ( !radio ), la función coords considera que el radio = r. De esta manera no necesitamos modificar las funciones que utilizan la función  coords con un solo parámetro ( a ).

function coords( a,radio ){
 radio = (!radio) ? r : radio;
 var arad = ( Math.PI / 180 ) * a;
 var coords = {
 "x" : cx + radio * Math.cos( arad ),
 "y" : cy + radio * Math.sin( arad )
 };
 return coords;
}

La función nuevaEtiqueta

Para  que el porcentaje aparezca en cada sector circular, empezamos dibujando un circulo imaginario cuyo radio representa dos tercios del radio del círculo base:

var radio = ( 2*r )/3;

A continuación calculamos las coordenadas ( x,y ) de un punto ac  situado en la circunferencia de este círculo, justo en el medio.

var ac = ap + ( af-ap )/2;
  var coordenadas = coords( ac, radio);
  var x = coordenadas.x;
  var y = coordenadas.y;

Creamos un nuevo elemento <text> ( nuevaEtiqueta ), y lo dotamos de atributos: id, x, y, fill, text-anchor y dominant-baseline. También establecemos  el contenido del elemento <text>.

var textNode = document.createTextNode(text);
nuevaEtiqueta.appendChild(textNode);

Finalmente la función nuevaEtiqueta añade la etiqueta al lienzoSVG

lienzoSVG.appendChild(nuevaEtiqueta);

function nuevaEtiqueta(ap,af,text){
	
	var radio = (2*r)/3;
	var ac = ap+(af-ap)/2;
	
	var coordenadas = coords(ac, radio);
	
	var x = coordenadas.x;
	var y = coordenadas.y;
	
	var textNode =  document.createTextNode(text);
	
	var nuevaEtiqueta=document.createElementNS("http:\/\/www.w3.org/2000/svg","text");
	nuevaEtiqueta.setAttributeNS(null,"id", "etiqueta"+i); 	
	nuevaEtiqueta.setAttributeNS(null,"x", x); 	
	nuevaEtiqueta.setAttributeNS(null,"y", y);
	nuevaEtiqueta.setAttributeNS(null,"fill", "#fff");
	nuevaEtiqueta.setAttributeNS(null,"text-anchor", "middle");
	nuevaEtiqueta.setAttributeNS(null,"dominant-baseline", "middle");
	nuevaEtiqueta.appendChild(textNode);
	
	lienzoSVG.appendChild(nuevaEtiqueta);
}

La función nuevaSombra

Necesitamos modificar la función nuevaSombra para que la "sombra" siga apareciendo al pasar con el ratón por encima del texto.

. . . .
sombraSet.setAttributeNS(null,"begin", "gajo"+i+".mouseover; sombra"+i+".mouseover; texto"+i+".mouseover; etiqueta"+i+".mouseover" );
sombraSet.setAttributeNS(null,"end", "gajo"+i+".mouseleave; sombra"+i+".mouseleave; texto"+i+".mouseleave; etiqueta"+i+".mouseleave");

El bucle for

Al final del bucle for tenemos que llamar la función nuevaEtiqueta. Observamos que si el "gajo" es demasiado pequeño, la etiqueta no encaja correctamente. Por lo tanto decidimos llamar la función nuevaEtiqueta solo si el porcentaje > 4.

for( var i=0; i < oGrafico.length; i++ ){
   var porcentaje = oGrafico[ i ].porcentaje;
   var color = oGrafico[ i ].color;
   var nombre = oGrafico[ i ].nombre;
   // calcula el valor del ángulo
   af[ i ] = ((porcentaje*360)/100);
   if( i > 0 ){
   af[ i ] += af[ i-1 ]
   ap[ i ] = af[ i-1 ];
   } else { ap[ i ] = 0; }
   // llama las funciones necesarias
   nuevoGajo(ap[ i ],af[ i ],color,i);
   nuevaSombra(ap[ i ],af[ i ],color,i);
   leyenda(( i*30 ), color, nombre);
    if(porcentaje > 4){
    nuevaEtiqueta(ap[ i ],af[ i ],porcentaje+"%");
    }
  }

Veamos como queda

Ahora en cada sector circular aparece el porcentaje que este ocupa.

<svg id="lienzoSVG" width="400" height="240" >
<g id="grupLeyenda" transform ="translate(270,30)"></g>
</svg>

var lienzoSVG = document.getElementById("lienzoSVG");
var grupLeyenda = document.getElementById("grupLeyenda");
  
var cx = 130;
var cy = 120;
var r = 100;
 
var oGrafico = [
{nombre:"vitamina A", porcentaje:"40",color:"#0140CA"},
{nombre:"vitamina B", porcentaje:"12",color:"#DD1812"},
{nombre:"vitamina C", porcentaje:"6",color:"#16A6FE"},
{nombre:"vitamina D", porcentaje:"17",color:"#6ab150"},
{nombre:"vitamina E", porcentaje:"25",color:"#FCCA03"}
];
 
function coords( a,radio ){
 radio = (!radio) ? r : radio;
 var arad = ( Math.PI / 180 ) * a;
 var coords = {
 "x" : cx + radio * Math.cos( arad ),
 "y" : cy + radio * Math.sin( arad )
 };
 return coords;
}
 
function dGajo(ap,af){
var Xap = coords( ap ).x;
var Yap = coords( ap ).y;
var Xaf = coords( af ).x;
var Yaf = coords( af ).y;
var parametro_d  = 
   "M" + cx + ", " + cy+
   " L"+Xap+","+Yap+ 
   " A"+r+","+r+" 0 0, 1 "+Xaf+","+Yaf+ 
   " z";
   return parametro_d;
	 }
 	
function dSombra( ap,af ){
var Xap = coords( ap ).x;
var Yap = coords( ap ).y;
var Xaf = coords( af ).x;
var Yaf = coords( af ).y;		
var parametro_d  = 
   "M" + Xap + ", " + Yap+
   " A"+r+","+r+" 0 0, 1"+Xaf+","+Yaf;
   return parametro_d;
	}
 
function nuevaSombra(ap,af,color,i){
 
var nuevaSombra=document.createElementNS("http:\/\/www.w3.org/2000/svg","path");
nuevaSombra.setAttributeNS(null,"id", "sombra"+i); 		
nuevaSombra.setAttributeNS(null,"d", dSombra(ap,af));
nuevaSombra.setAttributeNS(null,"fill", "none"); 
nuevaSombra.setAttributeNS(null,"stroke", color);
nuevaSombra.setAttributeNS(null,"stroke-opacity", .4); 
nuevaSombra.setAttributeNS(null,"stroke-width", 0);
 
lienzoSVG.appendChild(nuevaSombra);
 
var sombraSet = document.createElementNS("http:\/\/www.w3.org/2000/svg","set");
sombraSet.setAttributeNS(null,"attributeName", "stroke-width");
sombraSet.setAttributeNS(null,"attributeType", "XML");
sombraSet.setAttributeNS(null,"to", 15);
sombraSet.setAttributeNS(null,"begin", "gajo"+i+".mouseover; sombra"+i+".mouseover; texto"+i+".mouseover; etiqueta"+i+".mouseover" );
sombraSet.setAttributeNS(null,"end", "gajo"+i+".mouseleave; sombra"+i+".mouseleave; texto"+i+".mouseleave; etiqueta"+i+".mouseleave");
 
nuevaSombra.appendChild(sombraSet);
}
 
function nuevoGajo(ap,af,color,i){
var nuevoGajo=document.createElementNS("http:\/\/www.w3.org/2000/svg","path");
nuevoGajo.setAttributeNS(null,"id", "gajo"+i); 			
nuevoGajo.setAttributeNS(null,"d", dGajo(ap,af));
nuevoGajo.setAttributeNS(null,"fill", color); 
nuevoGajo.setAttributeNS(null,"stroke", "#fff"); 
nuevoGajo.setAttributeNS(null,"stroke-width", "2"); 
lienzoSVG.appendChild(nuevoGajo);
}

function leyenda(y,color,texto){
	var nuevoRect=document.createElementNS("http:\/\/www.w3.org/2000/svg","rect");
	nuevoRect.setAttributeNS(null,"x", "0"); 
	nuevoRect.setAttributeNS(null,"y", y);
	nuevoRect.setAttributeNS(null,"width", 20);
	nuevoRect.setAttributeNS(null,"height", 20);
	nuevoRect.setAttributeNS(null,"fill", color);
	grupLeyenda.appendChild(nuevoRect);
	
	var nuevoTexto=document.createElementNS("http:\/\/www.w3.org/2000/svg","text");
	nuevoTexto.setAttributeNS(null,"x", "30"); 
	nuevoTexto.setAttributeNS(null,"y", parseInt(y+18));
	
	var textoNode =  document.createTextNode(texto);	
	nuevoTexto.appendChild(textoNode);
	
	grupLeyenda.appendChild(nuevoTexto); 
}

function nuevaEtiqueta(ap,af,text){
	
	var radio = (2*r)/3;
	var ac = ap+(af-ap)/2;
	
	var coordenadas = coords(ac, radio);
	
	var x = coordenadas.x;
	var y = coordenadas.y;
	
	var textNode =  document.createTextNode(text);
	
	var nuevaEtiqueta=document.createElementNS("http:\/\/www.w3.org/2000/svg","text");
	nuevaEtiqueta.setAttributeNS(null,"id", "etiqueta"+i); 	
	nuevaEtiqueta.setAttributeNS(null,"x", x); 	
	nuevaEtiqueta.setAttributeNS(null,"y", y);
	nuevaEtiqueta.setAttributeNS(null,"fill", "#fff");
	nuevaEtiqueta.setAttributeNS(null,"text-anchor", "middle");
	nuevaEtiqueta.setAttributeNS(null,"dominant-baseline", "middle");
	nuevaEtiqueta.appendChild(textNode);
	
	lienzoSVG.appendChild(nuevaEtiqueta);
	
}

var ap = Array(); // angulos de partida
var af = Array(); // angulos finales


   
for( var i=0; i < oGrafico.length; i++ ){
   var porcentaje = oGrafico[ i ].porcentaje;
   var color = oGrafico[ i ].color;
   var nombre = oGrafico[ i ].nombre;
   // calcula el valor del ángulo
   af[i] = ((porcentaje*360)/100);
   
   if( i>0 ){
      af[ i ] += af[ i-1 ]
      ap[ i ] = af[ i-1 ];
    } else { ap[ i ] = 0; }
   // llama las funciones necesarias
   nuevoGajo(ap[ i ],af[ i ],color,i);
   nuevaSombra(ap[ i ],af[ i ],color,i);
   leyenda((i*30),color,nombre);
   if(porcentaje > 4){
   nuevaEtiqueta(ap[ i ],af[ i ],porcentaje+"%");
   }
}

No te olvides: siempre que sea posible, pon el JavaScript dentro del <body>, justo antes de su cierre: los estilos arriba, los scripts al fondo.