En mi primera publicación sobre la creación de gráficos, miré métodos que se basaban únicamente en CSS. Argumenté que esta no era la mejor opción en la mayoría de los casos; hay demasiados obstáculos complicados de diseño y desarrollo que superar. En términos generales, es mejor crear gráficos con una combinación de SVG, JavaScript y CSS.
Por qué no canvas
?
Hay muchas otras formas en las que puede crear un gráfico para la web, sobre todo mediante el uso de canvas
elemento. Sin embargo, Sara Soueidan también sugiere evitar este método:
HTML5 Canvas también se puede utilizar para crear tales visualizaciones, pero el contenido del lienzo no forma parte del DOM y, por lo tanto, los lectores de pantalla no pueden acceder a él. Debería crear un contenido secundario entre la apertura y el cierre. <canvas>
etiquetas para que sirvan como respaldo y como contenido accesible. También debe tomar medidas adicionales para mapear el contenido y la interactividad entre el contenido del lienzo y el respaldo, de modo que los lectores de pantalla sepan con qué elemento se está interactuando. Por lo tanto, un Canvas HTML5 requeriría el doble de mantenimiento. […] Con SVG, obtiene semántica y accesibilidad, así como interactividad con JavaScript lista para usar.
Sin embargo, existen alternativas a este canvas
Acercarse. Por ejemplo, Filament Group creó un complemento jQuery llamado Visualize, que toma los datos de un table
elemento y luego crea un canvas
gráfico. Esta práctica tiene mucho sentido, incluso si el elemento por sí solo no es el más adecuado para la tarea de creación de gráficos.
¿Por qué SVG?
El formato de imagen SVG no es solo para iconos o imágenes simples. Tiene ventajas que también se aplican a la creación de gráficos. En nuestro compendio de SVG describimos las ventajas generales del formato así:
- Tamaños de archivo pequeños que se comprimen bien
- Escala a cualquier tamaño sin perder claridad (excepto tamaños muy pequeños)
- Se ve muy bien en pantallas retina
- Control de diseño como interactividad y filtros
Podemos actualizar esto con dos puntos clave más que son útiles para los gráficos:
- Los archivos SVG son accesibles para los lectores de pantalla (con un poco de trabajo)
- Hay muchos marcos de gráficos basados en SVG para ayudar
Empecemos. ¿Cuál es el enfoque más simple para hacer un gráfico con SVG?
Gráficos con <img>
Hacer un gráfico con SVG puede ser tan fácil como diseñar uno en Illustrator, o la aplicación de diseño basada en vectores que elijas, exportarlo como SVG y colocarlo directamente en el marcado usando un <img>
etiqueta:
<img src="https://css-tricks.com/how-to-make-charts-with-svg/chart.svg" alt="Hopefully you can impart equally useful alternate content here.">
Esto es genial porque se verá bien y escalará bien. Sin embargo, perderemos la mayoría de los beneficios del SVG en línea, como la accesibilidad y la interactividad. Aparte del texto alternativo, los lectores de pantalla no leerán nuestros datos en voz alta y los puntos de datos en los gráficos mismos no podrán interactuar con la entrada del mouse, el tacto o el teclado.
Estos problemas sugieren que deberíamos usar otra técnica de incrustación de SVG si queremos obtener el mayor control posible sobre ellos. Por ejemplo, ¿qué sucede si estuviéramos trabajando en un proyecto como Death from Above, donde la naturaleza interactiva de los gráficos nos ayuda enormemente a comprender los datos?
Para aprovechar al máximo SVG, debemos tomar todo ese código y colocarlo directamente en nuestro marcado. De esa manera, podemos diseñar el gráfico con CSS, controlar la interactividad con JavaScript y obtener todos los beneficios de accesibilidad de SVG en línea.
(Podríamos obtener beneficios similares con <object>
o <iframe>
SVG incrusta, pero el concepto es tan similar, sigamos adelante con SVG en línea).
Gráfica de barras
Cada columna de nuestro gráfico estará contenida dentro de un <g>
elemento (en lenguaje SVG, esto es solo un grupo de elementos relacionados), dentro de cada uno de estos colocaremos un rect
elemento que define la forma de la columna, y un text
elemento que nos permite imprimir el número en la pantalla. Aquí hay un ejemplo terminado:
Vea el gráfico de barras Pen Simple en SVG por Programar Plus(@ css-tricks) en CodePen.
Podemos posicionar estos <rect>
y <text>
elementos con el estándar x
/y
coordenadas, así:
<svg class="chart" width="420" height="150" aria-labelledby="title desc" role="img">
<title id="title">A bar chart showing information</title>
<desc id="desc">4 apples; 8 bananas; 15 kiwis; 16 oranges; 23 lemons</desc>
<g class="bar">
<rect width="40" height="19"></rect>
<text x="45" y="9.5" dy=".35em">4 apples</text>
</g>
<g class="bar">
<rect width="80" height="19" y="20"></rect>
<text x="85" y="28" dy=".35em">8 bananas</text>
</g>
<g class="bar">
<rect width="150" height="19" y="40"></rect>
<text x="150" y="48" dy=".35em">15 kiwis</text>
</g>
<g class="bar">
<rect width="160" height="19" y="60"></rect>
<text x="161" y="68" dy=".35em">16 oranges</text>
</g>
<g class="bar">
<rect width="230" height="19" y="80"></rect>
<text x="235" y="88" dy=".35em">23 lemons</text>
</g>
</svg>
¿Observa que puede colocar el cursor sobre los elementos para cambiar el color de la barra y el color del texto? Esto es posible con el fill
Propiedad CSS:
.bar {
fill: red; /* changes the background */
height: 21px;
transition: fill .3s ease;
cursor: pointer;
font-family: Helvetica, sans-serif;
}
.bar text {
color: black;
}
.bar:hover,
.bar:focus {
fill: black;
}
.bar:hover text,
.bar:focus text {
fill: red;
}
¡Bien por los SVG interactivos y sencillos!
Sin embargo, aquí hay un problema: tabular el gráfico no funcionará (porque los navegadores no admiten la focusable
atributo todavía). Léonie Watson tiene sugerencias de accesibilidad para SVG que sugieren que puede usar <a xlink:href="https://css-tricks.com/how-to-make-charts-with-svg/#">
enlaces para la capacidad de enfoque, pero ¿qué pasa si el área enfocable no es realmente un enlace?
Pronto profundizaremos en esto con los próximos artículos.
Líneas de chispa
Dado que las líneas de chispa son efectivamente gráficos de barras diminutos, podemos usar gran parte del mismo código que antes para hacer este ejemplo:
Vea el gráfico de barras Pen Simple en SVG por Programar Plus(@ css-tricks) en CodePen.
Esta vez para alinear cada uno g
elemento uno al lado del otro, podemos usar un CSS en línea transform
en su lugar (probablemente sea mejor ceñirse a las coordenadas xey estándar, pero esto demuestra que es posible). Entonces cambiaremos el height
atributo en el rect
elemento para mostrar los datos correctamente, y empuje cada elemento hacia abajo desde la parte superior con el y
coordinar. Esto debería alinear cada barra con la parte inferior de la línea de chispa. Aquí hay un ejemplo de código abreviado:
<g class="bar" transform="translate(0,0)">
<rect height="10" y="10" width="3"></rect>
</g>
<g class="bar" transform="translate(3,0)">
<rect height="6" y="14" width="3"></rect>
</g>
Gráficos de líneas
Para marcar los puntos de datos de un gráfico de líneas podemos usar el polyline
elemento y el points
atributo:
<svg viewBox="0 0 500 100" class="chart">
<polyline
fill="none"
stroke="#0074d9"
stroke-width="3"
points="
0,120
20,60
40,80
60,20"/>
</svg>
0,120
en este ejemplo significaría 0 desde la izquierda y 120 desde la parte superior del lienzo SVG. Y una vez que tengamos lista nuestra lista de puntos de datos, podemos definir el ancho de la línea con stroke-width
y el color de esa línea con stroke
:
Vea el Pen e742b827fb9d04df80c56f3fea55c031 de Programar Plus(@ css-tricks) en CodePen.
Pero esto solo estiliza los datos, ¿qué pasa con esas líneas vitales que ayudan a todos a descifrar los puntos por sí mismos? ¿Y los ejes?
Haciendo los ejes y las etiquetas
Roemer Vlasveld hizo un gran tutorial sobre el desarrollo de gráficos con SVG y documenta algunas propiedades interesantes que nos ayudarán a etiquetar y diseñar cada eje de un gráfico. Tomaremos una versión simplificada de su trabajo para el siguiente ejemplo:
<svg class="graph">
<g class="grid x-grid">
<line x1="90" x2="90" y1="5" y2="371"></line>
</g>
<g class="grid y-grid">
<line x1="90" x2="705" y1="370" y2="370"></line>
</g>
</svg>
Cada g
se utilizará para crear las líneas horizontales y verticales y, cuando se combinan con las etiquetas de texto colocadas correctamente, esto da como resultado nuestros estilos básicos y marcado para un gráfico de dispersión, solo que sin los datos:
Vea el Pen 0c0f74831368af3bc93a8d146d85744e de Programar Plus(@ css-tricks) en CodePen.
Después de agregar cada punto de nuestros datos como una serie de circle
s dentro de otro g
elemento podemos ver cómo esto podría verse como un gráfico de dispersión:
Vea el Pen cb00290fb3ee28378498eca296d7c395 de Programar Plus(@ css-tricks) en CodePen.
Gráficos circulares
Hemos mencionado el artículo de Lea Verou sobre gráficos circulares un par de veces porque es un manual excelente para comenzar. No repetiré su técnica en detalle aquí, aunque creo que sería interesante ver cómo podemos hacer que estos gráficos circulares SVG sean interactivos. Aquí hay un ejemplo terminado para darle una idea de hacia dónde nos dirigimos:
Vea el gráfico SVG interactivo de Pen de Programar Plus(@ css-tricks) en CodePen.
Cuando se hace clic en uno de esos botones sobre el gráfico circular, el gráfico se actualizará con el valor almacenado en un objeto JavaScript. Este método puede tener problemas de accesibilidad, pero en lo que quiero centrarme es en la combinación interactiva de JavaScript y SVG.
Primero el marcado:
<figure>
<figcaption>
Percentage of world population by continent
</figcaption>
<div class="buttons"></div>
<svg width="100" height="100" class="chart">
<circle r="25" cx="50" cy="50" class="pie"/>
</svg>
</figure>
Entonces podemos configurar nuestros datos de población, así:
var continents = {
asia: 60,
northAmerica : 5,
southAmerica: 9,
oceania: 1,
africa: 15,
europe: 12
};
Lo que queremos hacer aquí es llenar el vacío. .buttons
div con una serie de botones que, al hacer clic, cambiarán el stroke-dasharray
propiedad de la circle
Elemento SVG. Podemos crear esos botones así:
var buttons = document.querySelector('.buttons');
for(property in continents) {
var newEl = document.createElement('button');
newEl.innerText = property;
newEl.setAttribute('data-name', property);
buttons.appendChild(newEl);
}
A continuación, necesitaremos corregir esos porcentajes ya que asia: 60
en nuestro continents
objeto significa 60 de 100 y no 60 de la circunferencia de nuestro círculo. Podemos hacer una función para solucionar esto por nosotros:
var total = 158;
var numberFixer = function(num){
var result = ((num * total) / 100);
return result;
}
Desde allí podemos agregar un detector de eventos a cada uno de esos botones y hacer una nueva función llamada setPieChart()
que cambia el valor de stroke-dasharray
comprobando dos veces el data-name
atributo de cada botón y encontrar el continente correspondiente en nuestro objeto:
buttons.addEventListener('click', function(e){
if(e.target != e.currentTarget) {
var el = e.target,
name = el.getAttribute('data-name');
setPieChart(name);
setActiveClass(el);
}
e.stopPropagation();
});
var setPieChart = function(name) {
var number = continents[name],
fixedNumber = numberFixer(number),
result = fixedNumber + ' ' + total;
pie.style.strokeDasharray = result;
}
Y una vez que hemos agregado algunas funciones auxiliares para agregar un estilo activo a los botones, tenemos un gráfico circular interactivo completamente funcional:
Vea el gráfico SVG interactivo de Pen de Programar Plus(@ css-tricks) en CodePen.
Manipular SVG con CSS y JavaScript
Animar los cambios en el ejemplo anterior fue relativamente sencillo, todo lo que tuvimos que hacer fue usar el transition
propiedad en CSS, así:
circle {
transition: stroke-dasharray .3s ease;
}
Luego, una vez que cambiamos la propiedad con nuestro script, CSS haría toda la animación por nosotros. Pero, ¿qué otras propiedades y atributos de SVG se pueden manipular con CSS?
Bueno, una de las peculiaridades de diseñar SVG con CSS es que solo hay ciertas propiedades que podemos controlar. Si queremos cambiar el x
o y
coordenadas de un g
por ejemplo (sin usar CSS transform
propiedad), entonces necesitaremos usar JavaScript. Lo que hace que esto sea aún más extraño si no está familiarizado con la sintaxis de SVG es que las propiedades de CSS afectarán a ciertos elementos, pero no a otros.
Hay una lista útil de propiedades del W3C que muestra qué propiedad afecta a qué elemento SVG, así que asegúrese de verificar esa lista si no ve lo que espera al diseñarlos.
Editar SVG a mano no es una solución perfecta
Con las otras formas básicas, incluyendo rect
, line
y polygon
podemos hacer cualquier tipo de gráfico SVG que nuestro corazón desee. La verdadera pregunta es esta: ¿realmente queremos? Por ejemplo, los gráficos de líneas son ciertamente posibles de hacer cuando estás editando un SVG a mano, pero no lo recomendaría necesariamente ya que la sintaxis es un poco compleja, especialmente si quisieras hacer algo como curvar la línea.
Escribir SVG a mano puede resultar lento y frustrante. Incluso para gráficos simples, se tarda una eternidad en escribir el código y posicionar visualmente cada sección. Al igual que la solución de solo CSS para hacer gráficos, es probable que su experiencia de hacer un gráfico con SVG a mano sea una experiencia dolorosa a menos que esté haciendo algo muy pequeño.
Debe haber una mejor manera, ¿verdad?
¡Frameworks al rescate!
En un próximo artículo, discutiremos todos los beneficios (y problemas) de usar un marco de gráficos para ayudarnos a hacerlos un poco más fáciles de producir. Compararemos todos los marcos de creación de gráficos populares y veremos cómo es visualizar datos de una manera más productiva y emocionalmente saludable.
Más información
- Muerte desde arriba infografía
- Consejos para crear archivos SVG accesibles
- Mega lista de Programar Plusde información SVG
- Lea Verou en gráficos circulares SVG
- Libro de O’Reilly sobre gráficos interactivos y visualización de datos
- Dibujo de líneas animadas en SVG