Saltar al contenido

Árbol y gráficos

Esta página está traducida del inglés. Leer la página en inglés

Tree

Tree::of(action) muestra una jerarquía que se carga bajo demanda. La acción recibe un TreeQuery y devuelve los hijos de q.parent (None para el nivel superior). Una rama carga sus hijos la primera vez que se abre, así que un árbol sobre una jerarquía grande cuesta una petición pequeña por cada rama abierta.

#[action(permission = "stock.product.read")]
pub async fn sample_tree(q: TreeQuery, store: SampleStore) -> Result<Vec<TreeItem>> {
    Ok(match q.parent.as_deref() {
        None => vec![TreeItem::branch("piece", "Piece"), TreeItem::branch("kg", "Kilogram")],
        Some(unit) => store.by_unit(unit)?.into_iter().map(|s| TreeItem::leaf(s.id.0.to_string(), s.name).hint(s.code)).collect(),
    })
}

Tree::of(sample_tree).label("Products by unit")
  • Cargando…

El árbol sigue el patrón ARIA tree: las teclas de flecha se mueven entre elementos y abren o cierran ramas. El servidor limita el número de hijos por rama (MAX_TREE_CHILDREN).

Gráficos

Chart::bar, stacked_bar, line, area, combo, scatter, donut, gauge y funnel dibujan SVG en el servidor. No hay biblioteca de gráficos en el navegador; un gráfico es parte del HTML de la página.

Row::new()
    .col(Chart::bar("Sales").labels(["Jan", "Feb", "Mar", "Apr", "May", "Jun"])
        .series("2025", [120.0, 98.0, 143.0, 160.0, 151.0, 189.0])
        .series("2026", [131.0, 122.0, 150.0, 171.0, 166.0, 204.0]))
    .col(Chart::donut("Units").labels(["Piece", "Kg", "Liter"]).series("Products", [40.0, 40.0, 40.0]))

Chart::stacked_bar("Channels").labels(months).series("Shop", shop).series("Web", web)
Chart::combo("Sales and margin").labels(months).series("Sales", sales).line_series("Margin %", margin).right_axis()
Chart::area("Visits").labels(months).series("Visits", visits)
Chart::scatter("Price and units").points("Tea", [(1.5, 40.0), (2.5, 22.0)])
Chart::gauge("Capacity").value(72.0).range(0.0, 100.0).target(85.0)
Chart::funnel("Checkout").labels(["Visited", "Cart", "Paid"]).series("People", [1000.0, 420.0, 150.0])

Revenue

184.250

Sube un 12,4% respecto al periodo anterior

Objetivo 200.000, 92% alcanzado

Average wait

6,5 min

Baja un 9,0% respecto al periodo anterior

Sales
Gráfico de barras de 2 series en 6 categorías. Máximo: Jun, 2026, 204.050100150200250JanFebMarAprMayJun
  • 2025
  • 2026
Mostrar datos
Datos de Sales
20252026
Jan120131
Feb98122
Mar143150
Apr160171
May151166
Jun189204
Units
Gráfico de anillo de 3 partes. Mayor: Piece, 40.120
  • Piece
  • Kg
  • Liter
Mostrar datos
Datos de Units
Products
Piece40
Kg40
Liter40
Sales and margin
Gráfico combinado de barras y líneas de 2 series en 6 categorías. Máximo: Jun, Sales, 189.050100150200JanFebMarAprMayJun0510152025
  • Sales
  • Margin %
Mostrar datos
Datos de Sales and margin
SalesMargin %
Jan12018
Feb9814
Mar14321
Apr16022
May15119
Jun18924
Capacity
Indicador en 72, entre 0 y 100. Objetivo: 85.720100
Mostrar datos
Datos de Capacity
ValorMínimoMáximoObjetivo
72010085

Cada gráfico tiene un título, un resumen en texto para lectores de pantalla, una leyenda y sus números como tabla bajo Show data. Los colores de las series son los tokens --z-chart-1 a --z-chart-6; una prueba (chart_colors_reach_three_to_one_in_both_themes) comprueba 3:1 frente a --z-surface y --z-surface-2 en el tema claro y en los dos temas oscuros (consulta Theming).

Cada barra, punto, porción, etapa y valor de gauge es una marca con su etiqueta y su valor como nombre. El SVG es un grupo con el nombre del título y del resumen, y el gráfico es una sola parada de tabulación:

TeclaQué hace
TabEntra en el gráfico, en la marca enfocada por última vez (la primera al principio)
Izquierda, DerechaMarca anterior o siguiente de la misma serie (se invierten con dir="rtl")
Arriba, AbajoEl mismo punto de la serie anterior o siguiente
Inicio, FinPrimera o última marca de la serie
EscapeOculta el tooltip

El cursor, el foco y un toque muestran el mismo texto en un tooltip, que se oculta a los lectores de pantalla para que nada se lea dos veces. Sin el script las marcas siguen teniendo nombre y la tabla permanece. Las marcas pequeñas (puntos de 8 px) están por debajo del tamaño de objetivo de 24 px; la tabla bajo Show data es el camino equivalente (WCAG 2.5.8).

Cifras clave, sparklines y bullets

Kpi muestra un valor, su cambio frente al periodo anterior con una flecha y palabras para la dirección (verde cuando el cambio es bueno, rojo cuando no; .lower_is_better() para costes y esperas), un objetivo con la proporción alcanzada y un sparkline de valores recientes.

Kpi::new("Revenue this month", 184_250.0).delta(12.4).target(200_000.0).trend([140.0, 152.0, 160.0, 184.0])
Kpi::new("Average wait", 6.5).decimals(1).unit("min").delta(-9.0).lower_is_better()

En un DataGrid, una columna Vec<f64> se dibuja como sparkline y una columna de número o dinero como bullet frente a un objetivo:

DataGrid::of(search_reps)
    .column(Rep::sales).cell(BulletCell::new(80_000.0, 120_000.0))
    .column(Rep::weeks).cell(SparklineCell::new())

Ambos son un SVG pequeño por celda con un nombre como "Trend of 12 values from 40 to 61, lowest 12, highest 99". Presupuesto: unos 0,65 KB de HTML por fila para las dos celdas; 10.000 filas de ambas se renderizan en unos 0,4 s en una compilación de depuración (sparkline_and_bullet_cells_render_ten_thousand_rows_quickly), y las tablas solo renderizan las filas visibles. charts.js añade 3,7 KB sin comprimir (1,4 KB con gzip) y charts.css 3,3 KB (1,1 KB con gzip).