Gráficos circulares (3)
Añadir una leyenda
Además de dibujar el gráfico, necesitamos una leyenda, una explicación del significado de los colores que aparecen en el gráfico. Lo que queremos conseguir es algo parecido al siguiente ejemplo.
Para cada elemento del array oGrafico
queremos dibujar un pequeño rectángulo de 20px/20px relleno del color correspondiente: oGrafico[ i ].color
. A unos 30px del origen del rectángulo tiene que aparecer su significado, en este caso el nombre: oGrafico[ i ].nombre
.
El siguiente elemento tiene las mismas coordenadas x
que el anterior, mientras que el y
crece en 30px.
Modificamos el HTML
En el HTML añadimos un grupo <g id="leyenda". . .
un contenedor donde colocar los rectángulos y el texto que componen la leyenda. Trasladamos el grupo, alla donde queremos que esté, utilizando transform = "translate(x,y)"
<svg id = "lienzoSVG" width= "400" height= "240" >
<g id= "grupLeyenda" transform = "translate(270,30)"></g>
</svg>
La función leyenda
Escribimos una function que construye una por una las entradas de la leyenda: un rectángulo de color y el texto correspondiente.
Para ser más exactos, la función leyenda construye el rectángulo <rect>
, establece sus atributos ( x
, y
, width
, height
y fill
) y lo añade al grupo <g id="grupLeyenda"
.
El atributo x = 0
, ya que ulteriormente desplazamos todo el grupo utilizando transform = "translate(x,y)"
También crea un elemento <text>
( textoNode
) y establece sus atributos ( x
e y
).
Utiliza document.createTextNode
para crear un nodo de texto ( el contenido de nuevoTexto
).
var textoNode = document.createTextNode(texto);
nuevoTexto.appendChild(textoNode);
El valor del atributo x = 30
, ya que queremos que el texto empiece a 30px del origen del rectángulo.
Finalmente la función leyenda
añade el nuevoTexto
al grupo <g id="grupLeyenda
.
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);
}
El bucle for
También modificamos ligeramente el bucle for
. Para cada elemento del array oGrafico
recuperamos el nombre ( oGrafico[ i ].nombre
).
Al final del bucle llamamos la nueva función leyenda
, que toma tres atributos: el valor de la coordenada y
de cada entrada, el color
del rectángulo y el nombre
. Queremos que cada entrada empiece 30px más abajo que la anterior, por lo cual y = i * 30
.
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)
}
Veamos como queda
Ahora a la derecha aparece una leyenda con los colores utilizados y su significado.
<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 ){
var arad = ( Math.PI / 180 ) * a;
var coords = {
"x" : cx + r * Math.cos( arad ),
"y" : cy + r * 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");
sombraSet.setAttributeNS(null,"end", "gajo"+i+".mouseleave; sombra"+i+".mouseleave; texto"+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);
}
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)
}
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.
A continuación añadimos los porcentajes..