Gráficos circulares (Pie Charts) en puro Css. 27.2.13
Cómo hacer un gráfico circular (Pie Charts) en puro Css.
Gráficos circulares (Pie Charts) en puro Css.
La representación de datos en gráficos siempre es una ayuda para comprender y asimilar la información. Y los ejemplos realizados con puro Css, tanto los de barras como lineales, son ya veteranos.
Quizás de los que no haya tantas realizaciones sean de los gráficos circulares (en quesitos) hechos en puro Css. Así que este artículo va de un par de demos para hacer estos gráficos circulares. Como el de la imagen de la derecha.
Si eres de los que no te gusta jugar con Css tienes otras opciones (además de preguntarte cómo has llegado aquí) como puede ser la aplicación de Google Chart Wizard o aplicaciones de escritorio: hojas de cálculo o programas de edición vectoriales.
Gráfico circular Css con clip: rect()
Esta forma la encontré en el blog de Kyle Larson. El valor añadido por mi es el poder escalar el tamaño del gráfico de forma sencilla, que vemos al llegar ello.
Otra particularidad de esta realización es que puedes añadir sombra o borde. Y que la posición y tamaño de las porciones (que por aquello del trivial yo llamo "quesitos" en el código) es relativamente sencilla de entender y por lo tanto de aplicar. Tiene su lógica.
Gráfico circular Css por Kyle Larson
O veo la demo o no sigo leyendoLo primero es crear nuestro contenedor general para el gráfico y un elemento extra para aplicar un par de efectos: borde homogéneo y sombra:
* {
box-sizing: border-box;
}
.grafico {
height: 200px;
margin: 1rem auto;
position: relative;
width: 200px;
}
.sombra {
background-color: #fff;
border-radius: 50%;
box-shadow: 0 4px 7px rgba(0, 0, 0, 0.3);
border: 5px solid #000;
height: 100%;
position: absolute;
width: 100%;
}
<div class="grafico">
<div class="sombra"></div>
<!-- aquí irán las porciones -->
</div>
Todo los tamaños, tanto del gráfico como de los segmentos (no su arco) están en función de las medidas de .grafico y se colocan respecto a él al estar posicionado. Se le podrían declarar a esta caja el border-radius y overflow: hidden y así evitarnos tener que redondear cada porción, pero nos impediría aplicar el efecto de la sombra y afectaría a la hora de situar los segmentos.
El div .sombra es sólo a efectos ornamentales, así que si quieres puedes prescindir de él.El primer segmento del gráfico circular Css
Cada porción se consigue con dos elementos enlazados:
<div class="grafico">
<div class="sombra"></div>
<div id="porcion1" class="recorte">
<div class="quesito" data-rel="70"></div>
</div>
</div>
Las clases .recorte | .quesito son comunes a todos los segmentos que se creen. El id #porcionX cambia de quesito a quesito, siendo la que definirá su cuerda (tamaño), ubicación en el gráfico, el giro para su correcta colocación, background y otras particularidades de cada uno.
.recorte {
border-radius: 50%;
clip: rect(0px, 200px, 200px, 100px);
position: absolute;
height: 100%;
width: 100%;
}
.quesito {
border-radius: 50%;
clip: rect(0px, 100px, 200px, 0px);
position: absolute;
height: 100%;
width: 100%;
}
#porcion1 {
transform: rotate(0deg);
}
#porcion1 .quesito {
background-color: rgba(0,0,255,.7);
transform: rotate(70deg);
}
En esta demo la magia corre por cuenta de la propiedad clip: rect() Los valores utilizados en el paréntesis hacen un recorte en recto de cada div. El resultado de la combinación de los 2 recortes (padre e hijo) es el "quesito" o porción triangular con la base redondeada.
El mayor o menor espacio ocupado (valor) de cada porción se obtiene con el valor del giro dado a cada uno. Por eso el usar un id: #porcion1 .quesito{transform: rotate(70deg);}
Y la posición que ocupa cada uno de ellos en el círculo se controla con ayuda del giro dado: #porcion1 {transform: rotate(0deg);}.
A continuación sólo es cuestión de añadir tantas porciones como necesitemos para completar el gráfico, teniendo en cuenta tres detalles:
- Que la suma total del valor de los giros de todos los #porcionX .quesito debe ser 360. Si es menos habrá espacios vacíos y si más solapamientos.
- En las porciones de la parte izquierda del gráfico circular con Css (semicírculo izquierdo) conviene hacer el giro al contrario, esto es en valor negativo o contrario al giro de las agujas del reloj.
- La lógica para colocar cada quesito adyacente al precedente es que su punto de colocación (valor del giro de #porcionX+1 es la suma de los dos giros del que le precede = #porcionX + (#porcionX .quesito).
Lo valores de cada porción del gráfico
Una vez declaradas todas las porciones y colocadas en su lugar, sólo nos resta un detalle para que los valores de cada una se muestren también.
Para ello nos añadimos un atributo a cada quesito con su valor del tipo data-*. Así queda el marcado html de cada parte del gráfico Css, ya completo:
<div id="porcion3" class="recorte">
<div class="quesito" data-rel="25"></div>
</div>
Y para mostrarlo utilizamos en el pseudoelemento ese atributo y su valor en la propiedad content. Junto a unas declaraciones a mayores para posicionarlo sobre su color y contrarrestando el giro según el gusto o la necesidad de cada caso:
#porcion3 .quesito:after {
content: attr(data-rel);
position: absolute;
left: 35%;
top: 4%;
transform: rotate(70deg);
}
Y el resultado final, todo junto y con los prefijos privativos necesarios, así es como luce el gráfico circular en puro Css ya completo:
Check out this Pen!
Kseso
the obCSServer ᛯ Ramajero Argonauta, Enredique Amanuense de CSS.#impoCSSible inside
Dicen que, en español, EsCss es el mejor blog de CSS. Posíblemente exageren.
@Kseso EsCss Kseso
Interesante, muchas gracias.
ResponderEliminarBuen articulo
ResponderEliminarCreo que me perdí el artículo donde se explicaba clip: rect(); xD
ResponderEliminarParece ser que los límites de CSS están solo en la imaginación
ResponderEliminarBuen articulo, y en general excelente blog :D
Súper el aporte!!, que buen blog!!
ResponderEliminarCreo que no funciona si alguna de las porciones mide más de 180 grados
ResponderEliminar¿Si algún porcentaje fuese mayor a 50%?
EliminarHay que crearlo con más de una capa, obviamente. Pero no entiendo por qué no funcionaría.
De hecho, si al ejemplo le cambiamos
#porcion1 .quesito {
background-color: rgba(255,255,0,.7);
transform: rotate(70deg);
}
ya hay un ... (¿cómo le dice? ¡ah, sí!) "quesito" amarillo de más de 50%. Habrá que ajustar los números, pero se ve claramente que es posible.
Hola Diego.
EliminarSi te fijas, los quesitos están logrados en base a la propiedad clip que produce cortes rectos a 90º.
Recorta el sobrante de la caja generada. Por lo tanto no esperes obtener un trozo a mayores "por fuera".
Pero si tienes necesidad de mostrar una "porción" mayor a un semicírculo siempre puedes suplir con algo de imaginación lo que Css no permite.
Bastaría con usar el espacio libre del div "gráfico" para tener una porción mayor de 180º siempre que la suma del resto de "quesitos" cubran menos de la mitad.
Un saludo
Aquí tienes un fork del pen del artículo.
EliminarCreo que queda más claro que la explicación confusa de mi respuesta anterior.
Un saludo
Hola.
ResponderEliminarNo entiendo porque si le doy 350px de ancho y alto, se desarma todo y es re dificil porder volver a armarlo :(
Saludos.
Si pudieras publicar tu código o un enlace* a tu realización sería posible ver qué ocurre con ella.
EliminarDe esta forma, imposible, Roddy, una respuesta precisa y concreta a tu caso.
Sólamente recordarte que hay que controlar, además del tamaño, el valor de clip y el giro de cada uno de los "quesitos".
Un saludo
* Recuerda que puedes publicar código o insertar pens de Codepen
Muchas gracias por la respuesta.
Eliminarte dejo aqui el link http://dev.axionla.cl/infografia/ al estilo .grafico le di 350px de ancho y 350px de alto, al hacerlo los pedazos se desarman, y al tratar de manipular "clip: rect(0px, 200px, 200px, 100px)" no puedo lograr llegar a encajarlos, no se si logro explicarme.
un Saludo.
Creo que con el siguiente pen podrás observar la relación entre el tamaño de .grafico y los valores de la propiedad clip de .recorte y .quesito
EliminarLo mimo ocurre con el resto de las relaciones (tamaños y ubicación de cada porción) con los giros declarados.
Pero todo esto lo tienes detallado en el artículo.
Un saludo.
[pen]data-height="400" data-theme-id="299" data-slug-hash="QjLvRm" data-default-tab="result" data-user="Kseso" class='codepen'[/pen]
Oh muchisimas gracias.
Eliminarahora logre entender viendo el CSS, y gracias por ayudarme con esto. me saco de un apuro.
gracias por enseñar y por subir informacion valiosa para nosotros. siempre veo este blog.
Saludos.