Catálogo · Gráficos
Gráfico
Dibuja una línea, un área o una línea de tendencia pequeña a partir de una tabla o de una lista de números que ya escribiste, y que sigue en la página a su lado.
Encaja mejor en: cualquier sitio — una página que muestra una tendencia: un informe, un panel, una entrada con algunas cifras
Ejemplo
Paquetes por ruta durante seis meses, como una tabla que puedes leer y como un gráfico de líneas dibujado a partir de ella. El botón cambia el dibujo por la tabla; un lector de pantalla siempre tiene la tabla.
| Month | Sevilla | Cádiz | Jerez |
|---|---|---|---|
| Jan | 1,204 | 312 | 640 |
| Feb | 1,310 | 340 | 620 |
| Mar | 1,180 | 365 | 700 |
| Apr | 1,420 | 410 | 690 |
| May | 1,390 | 398 | 760 |
| Jun | 1,480 | 452 | 810 |
Una columna es una serie, hasta seis. Sin JavaScript es la tabla.
| Month | Sevilla |
|---|---|
| Jan | 1,204 |
| Feb | 1,310 |
| Mar | 1,180 |
| Apr | 1,420 |
| May | 1,390 |
| Jun | 1,480 |
Con variant="area".
- 41
- 38
- 44
- 52
- 47
- 58
- 63
type="spark": una línea pequeña y su última cifra como texto. Las otras seis quedan en la lista para un lector de pantalla.
Interactivo
Visitantes por día durante cuatro semanas, con interactive: cada serie y su total es un botón que apaga y enciende su línea, en la misma escala. Apunta a un día, o ve con Tab al gráfico y usa las flechas, para ver sus cifras y una banda sobre él. Sin JavaScript es la tabla. Los datos son de ejemplo: sustitúyelos por los tuyos.
| Day | Desktop | Mobile |
|---|---|---|
| Apr 1 | 252 | 148 |
| Apr 2 | 271 | 276 |
| Apr 3 | 182 | 128 |
| Apr 4 | 380 | 247 |
| Apr 5 | 194 | 203 |
| Apr 6 | 191 | 74 |
| Apr 7 | 179 | 98 |
| Apr 8 | 179 | 132 |
| Apr 9 | 281 | 217 |
| Apr 10 | 187 | 171 |
| Apr 11 | 193 | 251 |
| Apr 12 | 278 | 125 |
| Apr 13 | 228 | 152 |
| Apr 14 | 120 | 100 |
| Apr 15 | 331 | 270 |
| Apr 16 | 319 | 125 |
| Apr 17 | 317 | 259 |
| Apr 18 | 271 | 122 |
| Apr 19 | 226 | 121 |
| Apr 20 | 187 | 86 |
| Apr 21 | 146 | 130 |
| Apr 22 | 206 | 248 |
| Apr 23 | 200 | 256 |
| Apr 24 | 248 | 253 |
| Apr 25 | 378 | 284 |
| Apr 26 | 216 | 136 |
| Apr 27 | 190 | 153 |
| Apr 28 | 199 | 94 |
Problemas conocidos
Cuatro cosas que conviene saber antes de fiarse de él.
- Sin
interactiveno hay lectura de valores al pasar el puntero ni al enfocar: las cifras están en la tabla, que muestra el botón. Con él, la lectura sigue por igual al puntero y al foco. - Lee la tabla al conectarse, cuando la tabla cambia y cuando la caja cambia de tamaño. Una tabla añadida a la página más tarde, cuando esta ya cargó el script, necesita que el elemento se añada con ella.
- El trazado se dibuja de izquierda a derecha en todos los idiomas, como un eje de tiempo; la tabla, el título, la leyenda y el botón siguen la dirección de la página.
- No se ha probado con un lector de pantalla.
Código
Copia el marcado
import "@luz-ds/catalog/components/chart.css";
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@luz-ds/catalog@0.3.0/dist/components/chart.min.css" integrity="sha384-ELc0v0M/zEVoqPmwPSIjtJN98bz6vLurMqk58If0SOBFCqQT+JLI28PND1wWsOfG" crossorigin="anonymous">
Escribe primero la tabla, como la página en la que aterriza un lector sin JavaScript. La primera columna es el eje X, un th de su fila; cada una de las demás es una serie, con el nombre de su th. Pon cada número en un <data value> y escríbelo como quieres que se lea. Envuelve la tabla en un .luz-table-wrap solo cuando pueda ser más ancha que la pantalla, como en el ejemplo de tres series, y da a cada td un data-label para que en una pantalla estrecha sus filas se apilen y sigan nombrando sus celdas. Una tabla que siempre cabe no necesita contenedor: con uno, el grupo, la región y la tabla leerían el mismo nombre tres veces. El gráfico oculta el contenedor junto con la tabla y este no recibe parada de Tab mientras tanto.
catalog.min.js carga el archivo propio del elemento, chart.min.js, cuando analiza la página; una página sin catalog.min.js carga ese archivo por su cuenta. Enlaza components/chart.css, después del de core.
<script type="module" src="https://cdn.jsdelivr.net/npm/@luz-ds/catalog@0.3.0/dist/catalog.min.js"></script>
<luz-chart type="line" data-luz-label-table="Show table" data-luz-label-chart="Show chart">
<table class="luz-table">
<caption>Parcels per route, January to March</caption>
<thead>
<tr><th scope="col">Month</th><th scope="col">Sevilla</th><th scope="col">Cádiz</th></tr>
</thead>
<tbody>
<tr><th scope="row">Jan</th><td data-label="Sevilla"><data value="1204">1,204</data></td><td data-label="Cádiz"><data value="312">312</data></td></tr>
<tr><th scope="row">Feb</th><td data-label="Sevilla"><data value="1310">1,310</data></td><td data-label="Cádiz"><data value="340">340</data></td></tr>
<tr><th scope="row">Mar</th><td data-label="Sevilla"><data value="1180">1,180</data></td><td data-label="Cádiz"><data value="365">365</data></td></tr>
</tbody>
</table>
</luz-chart>
Con interactive, una cabecera con las series y sus totales, y una lectura de un día:
<luz-chart type="line" interactive data-luz-label-table="Show table" data-luz-label-chart="Show chart">
<table class="luz-table">
<caption>Visitors per day, April 1 to 3</caption>
<thead>
<tr><th scope="col">Day</th><th scope="col">Desktop</th><th scope="col">Mobile</th></tr>
</thead>
<tbody>
<tr><th scope="row">Apr 1</th><td><data value="252">252</data></td><td><data value="148">148</data></td></tr>
<tr><th scope="row">Apr 2</th><td><data value="271">271</data></td><td><data value="276">276</data></td></tr>
<tr><th scope="row">Apr 3</th><td><data value="182">182</data></td><td><data value="128">128</data></td></tr>
</tbody>
</table>
</luz-chart>
Una línea pequeña toma una lista de elementos <data>, en cualquier marcado, y muestra el último:
<luz-chart type="spark">
<span>Parcels a day, last 4 days</span>
<ul class="luz-chart__values" role="list">
<li><data value="41">41</data></li>
<li><data value="38">38</data></li>
<li><data value="44">44</data></li>
<li><data value="52">52</data></li>
</ul>
</luz-chart>
Tus scripts pueden preguntar qué dibujaría el gráfico:
import { readChart } from "@luz-ds/catalog/chart";
// What the chart draws: the names of the rows, and one series per column
const { rows, series } = readChart(document.querySelector("luz-chart"));
Variantes y opciones
| Clase o atributo | Efecto |
|---|---|
<luz-chart> | El elemento personalizado que define el módulo, alrededor de la tabla o de la lista. Se conecta solo al incorporarse |
type | line (por defecto) dibuja las columnas de la tabla; spark dibuja una línea pequeña con los elementos <data> que contiene. Con cualquier otro valor queda la tabla |
variant="area" | Rellena el área bajo cada línea con un tono suave del color de la serie |
interactive | Con type="line" (o type="column" en un gráfico de columnas): una cabecera con un botón por serie, su nombre y su total, que apaga y enciende su línea, y una lectura del día bajo el puntero o el foco. Sustituye a la leyenda |
data-luz-label-table, data-luz-label-chart | Las dos palabras del botón: «Ver tabla» y «Ver gráfico», en el idioma de la página, en el elemento o en un ancestro (una vez en <body> sirve a todos los gráficos). LUZ no tiene texto en inglés por defecto: si falta alguna no hay botón y la tabla se muestra bajo el gráfico |
--luz-chart-ratio | La forma del dibujo, 2 / 1 por defecto. Se define en el elemento: style="--luz-chart-ratio: 3 / 1" |
caption | El título: el pie de la tabla da nombre al grupo y se copia sobre el dibujo |
th scope="col" | El nombre de una serie, en la leyenda. La primera columna es el eje X; cada una de las demás es una serie, hasta seis, y las que sobran quedan solo en la tabla |
td con <data value> | Un número: el value de un <data> o el texto simple de la celda. Cualquier otra cosa es un hueco en la línea |
.luz-chart | La lista de un type="spark": los elementos <data> son los puntos y el último se muestra como texto |
data-luz-view, data-luz-ready, data-luz-end | Los escribe el script: chart, table o both según lo que se muestra; el elemento está listo; la última cifra de un spark. Dales estilo, nunca los pongas tú |
readChart(el) | Lo exporta @luz-ds/catalog/chart: los nombres de las filas y las series que contiene la tabla, o null |
Cómo funciona
CSS de @luz-ds/catalog y un archivo propio, @luz-ds/catalog/chart (dist/chart.min.js, menos de 5 kB comprimido), que define <luz-chart>. No usa ninguna biblioteca y dibuja solo con llamadas al DOM, así que una página que prohíbe scripts y estilos en línea lo ejecuta tal cual. Para comparar valores por longitud sin script, usa la lista de barras, el gráfico de columnas, la barra apilada o el mapa de calor.
- La tabla: sigue en la página. Mientras se muestra el gráfico, la tabla se saca de la pantalla, no se oculta, así que un lector de pantalla la lee como siempre; cuando el botón muestra la tabla, el dibujo desaparece. En papel se imprime la tabla y no el dibujo.
- El dibujo: un SVG marcado con
aria-hidden, dibujado de nuevo cuando cambia la caja o la tabla. No tiene animación. Las series son--luz-chart-1a--luz-chart-6, de modo que un cambio de modo no repinta nada. - Distinguir las series: cada línea termina en una marca de forma propia (un círculo, un cuadrado, un triángulo, un rombo, un más y una cruz), repetida en la leyenda. En colores forzados todas las líneas tienen el color del texto, cada una con sus propios guiones.
- Los números: la escala empieza en cero, o más abajo si una cifra es negativa, en pasos redondos (1, 2 o 5 veces una potencia de diez). Los ejes se escriben con
Intl.NumberFormaten el idioma de la página, como 1.2K. - Interactivo: la cabecera tiene un botón de alternancia por serie, con su nombre y la suma de sus cifras. El total es una suma: sirve para recuentos e importes, como visitantes o euros, y no para tasas, proporciones ni medias, cuyo total no dice nada. Una línea apagada ya no se dibuja, en la misma escala, y la última línea mostrada no se puede apagar. El día bajo el puntero, o la fila con el foco, recibe una banda clara y una lectura con su nombre y la cifra de cada línea mostrada, copiada de las celdas.
- Las palabras: el script no escribe ninguna propia. Las dos palabras del botón son tuyas, en
data-luz-label-*; el título y la leyenda copian tu pie de tabla y las cabeceras de tus columnas.
Sin JavaScript
La tabla, o la lista, es todo lo que hay, y está completa: el pie, todas las cifras, todos los nombres. El elemento es un bloque y el botón no existe. Con interactive tampoco hay cabecera ni lectura: todas las cifras están en la tabla. Es igual cuando la página no tiene la tabla o type no es uno de los dos.
Teclado y ARIA
- Teclas: Tab llega al botón «Ver tabla»; Enter o Espacio lo pulsan. Sin
interactive, nada en la imagen recibe el foco. - Interactivo: los botones de la cabecera son botones de alternancia (
aria-pressed): Enter o Espacio apagan y encienden una línea, y la última línea mostrada sigue encendida. Después, la imagen recibe el foco, en una sola parada de Tab. Es un grupo nombrado por el título de la tabla y contiene un estado de cortesía que, en cada tecla, dice la etiqueta del día, el mismo texto que la fila de la tabla. Cada fila se nombra con sus propias celdas, a partir de tu texto, «Apr 1, Desktop 252, Mobile 148», todas las series, mostradas o no. Con el foco en la imagen, las flechas pasan al día siguiente o al anterior (la flecha derecha es siempre el siguiente, porque el trazado va de izquierda a derecha), e Inicio y Fin al primero y al último; las teclas del modo de exploración de un lector de pantalla son suyas. Entrar dice su nombre y nada más, y salir vacía el estado. - La lectura: su título es el nombre del día, así que la banda nunca es la única señal de dónde estás. Escape la guarda sin mover el puntero ni el foco; vuelve en otro día. Está oculta para la tecnología de asistencia, que lee la fila. Una línea apagada no se dibuja, pero sus celdas siguen en la tabla, leídas como antes. El script escribe los roles de la tabla (
table,rowgroup,row,columnheader,rowheaderycell) para que las filas los conserven en todos los navegadores. - Nombre: el elemento es un grupo con el nombre del pie de la tabla, y el botón se describe con él, así que «Ver tabla» se oye junto con lo que muestra. El dibujo, su título y su leyenda son
aria-hidden: la tabla lo dice todo.
Contraste y foco están en la pestaña Diseño.
Diseño
Cuándo usarlo
Úsalo para mostrar cómo cambian unas pocas series a lo largo de un eje ordenado, como los meses, cuando la forma del cambio es lo que el lector debe ver y ya tienes los números en una tabla. Añade interactive para muchos días y dos o más series, cuando importan los totales y un día se lee de uno en uno. La línea pequeña (type="spark") es para una cifra que necesita su tendencia a su lado.
Cuándo no usarlo
No lo uses cuando importan más los valores exactos que la forma: una tabla los dice mejor. Para comparar unos pocos valores en una sola escala, usa un gráfico de columnas o una lista de barras, que no necesitan script.
- No lo uses para partes de un todo: usa una barra apilada. No hay gráficos circulares ni de anillo.
- No uses
interactivepara tasas, proporciones ni medias: el total de su cabecera es una suma. - No lo uses para más de seis series, ni para series que no pueden compartir escala: sepáralas en dos gráficos.
Sustituye a una biblioteca de gráficos que dibuja un lienzo sin texto a su lado. No se elimina nada de LUZ.
Qué hacer y qué no
Escribir el contenido
El pie es el título del gráfico y dice qué se cuenta, dónde y cuándo: «Paquetes por ruta, de enero a junio». Es el nombre que un lector de pantalla da al grupo.
- Nombra cada columna como debe leerse la leyenda, con su unidad si la tiene, y escribe cada cifra en su celda como quieres que se lea:
1,204, no1204, con el número simple en elvalue. - Escribe el botón como la acción y la cosa: «Ver tabla», «Ver gráfico». Define ambos en la página, una vez, en su idioma.
- Con
interactive, la cabecera de cada columna es también el nombre de su botón: una palabra o dos. - Mantén cortos los nombres de las filas: son las etiquetas del eje X y algunas se omiten cuando no caben.
Contraste y foco
Las seis series son colores de gráfico, cada una con 3:1 o más sobre la página y sobre una tarjeta, en todos los modos; ninguna es roja, verde ni amarilla, porque esos colores dicen un estado. La rejilla es una línea fina, más tenue que cualquier serie, porque las cifras están en la tabla.
| Parte | Color sobre fondo | Claro | Oscuro | Alto contraste | Necesita |
|---|---|---|---|---|---|
Serie 1, línea, marca y leyenda | --luz-chart-1 on --luz-surface-page | 5.6:1 | 7.7:1 | 14.1:1 | 3:1 |
Serie 2, línea, marca y leyenda | --luz-chart-2 on --luz-surface-page | 5.3:1 | 8.9:1 | 9.3:1 | 3:1 |
Serie 3, línea, marca y leyenda | --luz-chart-3 on --luz-surface-page | 9.6:1 | 10.6:1 | 10.9:1 | 3:1 |
Serie 4, línea, marca y leyenda | --luz-chart-4 on --luz-surface-page | 9.8:1 | 6.1:1 | 6.6:1 | 3:1 |
Serie 5, línea, marca y leyenda | --luz-chart-5 on --luz-surface-page | 3.9:1 | 5.0:1 | 6.2:1 | 3:1 |
Serie 6, línea, marca y leyenda | --luz-chart-6 on --luz-surface-page | 3.7:1 | 5.4:1 | 14.7:1 | 3:1 |
Serie 6, sobre una tarjeta | --luz-chart-6 on --luz-surface | 3.8:1 | 5.0:1 | 14.7:1 | 3:1 |
Cifras de los ejes y de la leyenda | --luz-text-secondary on --luz-surface-page | 6.2:1 | 7.5:1 | 19.3:1 | 4.5:1 |
Título | --luz-text-primary on --luz-surface-page | 15.8:1 | 15.1:1 | 21.0:1 | 4.5:1 |
Rejilla, sobre la página | --luz-chart-grid on --luz-surface-page | 1.4:1 | 1.7:1 | 3.2:1 | 1.3:1 |
Serie 1 sobre la banda de un día | --luz-chart-1 on --luz-surface-hover | 5.1:1 | 6.4:1 | 13.5:1 | 3:1 |
Serie 2 sobre la banda de un día | --luz-chart-2 on --luz-surface-hover | 4.8:1 | 7.4:1 | 8.9:1 | 3:1 |
Serie mostrada: su nombre y su total | --luz-text-primary on --luz-surface-muted | 15.8:1 | 15.1:1 | 20.1:1 | 4.5:1 |
Serie mostrada: la línea bajo ella | --luz-brand-primary on --luz-surface-muted | 5.6:1 | 7.7:1 | 13.5:1 | 3:1 |
Serie apagada: su nombre y su total | --luz-text-secondary on --luz-surface-page | 6.2:1 | 7.5:1 | 19.3:1 | 4.5:1 |
Lectura: la cifra | --luz-text-primary on --luz-surface-strong | 13.5:1 | 10.9:1 | 18.0:1 | 4.5:1 |
Lectura: el nombre de la serie | --luz-text-secondary on --luz-surface-strong | 5.3:1 | 5.4:1 | 16.5:1 | 4.5:1 |
Anillo de foco | --luz-focus-ring on --luz-surface-page | 5.6:1 | 7.7:1 | 21.0:1 | 3:1 |
Medido a partir de los valores de los tokens de cada modo, redondeado hacia abajo. Necesita es el mínimo de WCAG 2.2 AA: 4.5:1 para el texto, 3:1 para las líneas y las marcas; la rejilla es decorativa y conserva una línea fina de 1.3:1 o más.
- Foco: el botón «Ver tabla» es el botón fantasma de core y toma su anillo de foco. La imagen no recibe ninguno. Con
interactive, un botón de la cabecera toma el anillo de foco,--luz-focus-ring, de 2px, dentro de su borde, y también la imagen: el anillo se dibuja alrededor de ella, a 2px de su borde, porque es la imagen la que tiene el foco. - Objetivo y foco: cada botón de la cabecera interactiva mide más de 24 por 24 px (WCAG 2.2, 2.5.8), y la lectura se coloca junto al día que tiene el foco y nunca sobre él (2.4.11). Ambos criterios son nuevos en WCAG 2.2 y todavía no los exige EN 301 549 v3.2.1.
- Una serie se distingue por su color, por la marca con que termina y por la leyenda; en colores forzados todas las líneas tienen el color del texto, con sus propios guiones, el área no se rellena y la rejilla es el gris del texto. Una serie apagada tiene un punto hueco y un nombre más claro, y la banda de un día es un borde discontinuo en colores forzados.
Tokens que usa
Los 33 tokens que lee components/chart.css, por familia; el botón es de core. Cada familia enlaza a su página, con los valores en cada modo. En Figma son variables con los mismos nombres: consulta Tokens en Figma.
- Color
--luz-brand-primary,--luz-chart-1,--luz-chart-2,--luz-chart-3,--luz-chart-4,--luz-chart-5,--luz-chart-6,--luz-chart-grid,--luz-divider,--luz-focus-ring,--luz-surface-hover,--luz-surface-muted,--luz-surface-strong,--luz-text-primary,--luz-text-secondary- Espaciado y tamaños
--luz-space-2xl,--luz-space-2xs,--luz-space-3xs,--luz-space-lg,--luz-space-md,--luz-space-sm,--luz-space-xs- Tipografía
--luz-font-heading,--luz-font-mono,--luz-font-sans,--luz-text-sm,--luz-text-xl,--luz-text-xs- Radio
--luz-radius-full,--luz-radius-md,--luz-radius-sm- Sombras
--luz-shadow-md- Capas
--luz-z-raised
Teclado y ARIA están en la pestaña Código.