Saltar al contenido

Accesibilidad, impresión y edición posterior

Ver las tres consecuencias del modelo de imagen que no se notan hasta que es tarde: quién puede leer el gráfico, cómo se imprime y si alguien podrá modificarlo.

Accesibilidad: quién puede leer el gráfico

Un lector de pantalla no ve píxeles: recorre el árbol de accesibilidad, que se construye a partir del DOM. Esto tiene una consecuencia tajante.

Un SVG en línea produce nodos en ese árbol. Puedes darle un rol, un nombre accesible con <title>, una descripción larga con <desc>, y hacer que cada región relevante sea anunciable. Un gráfico de barras en SVG puede leerse serie a serie si lo estructuras bien.

Un raster —una imagen o un canvas— es opaco. Lo único que se puede exponer es un texto alternativo desde fuera. Para una foto eso basta: “retrato de una mujer en un mercado” es toda la información que hay. Para un gráfico de datos no basta ni de lejos, porque la información es la que está dentro.

El canvas tiene un mecanismo específico: el contenido de reserva, es decir, los nodos que pones dentro del elemento <canvas>. Los navegadores no los pintan, pero los exponen al árbol de accesibilidad. Es lo mínimo exigible y es mucho mejor que nada.

HTML
<canvas id="ventas" width="600" height="300" role="img"        aria-label="Ventas trimestrales de 2026">  <table>    <caption>Ventas trimestrales de 2026 en miles de euros</caption>    <tr><th>Trimestre</th><th>Ventas</th></tr>    <tr><td>T1</td><td>412</td></tr>    <tr><td>T2</td><td>488</td></tr>    <tr><td>T3</td><td>355</td></tr>    <tr><td>T4</td><td>601</td></tr>  </table></canvas>

Esa tabla no se ve nunca y contiene toda la información del gráfico. Es un patrón barato, correcto y sorprendentemente poco usado.

Conviene ser honesto sobre sus límites: el contenido de reserva funciona bien para un gráfico estático. Para un canvas interactivo, donde el usuario navega, selecciona y modifica, mantener sincronizado un árbol paralelo de elementos accesibles es un trabajo real y frágil, y el resultado nunca iguala al de una interfaz construida con elementos nativos.

Impresión: la resolución que hace falta

Una pantalla ronda los 96 píxeles CSS por pulgada; una impresora de oficina trabaja a 300 o 600 puntos por pulgada, y una imprenta a 300 líneas efectivas con más. La proporción es de tres a seis veces en cada eje, lo que significa entre nueve y treinta y seis veces más píxeles.

Un raster preparado para pantalla impreso a tamaño real se ve mal, y no hay remedio. Un vector se rasteriza a la resolución de la impresora en el momento de imprimir y sale perfecto.

Para el canvas hay una consecuencia concreta: al imprimir, el navegador manda a la impresora el búfer tal cual está, con su resolución de pantalla. No hay ningún mecanismo por el que el canvas se regenere más grande. Si el gráfico tiene que imprimirse bien, hay dos caminos.

El primero es generar una versión de alta resolución bajo demanda, redibujando la misma escena en un canvas auxiliar mucho más grande y sustituyendo la imagen en la vista de impresión.

JS
// Regenerar la escena a 4x para imprimirfunction exportarParaImprimir(dibujarEscena, ancho, alto, factor = 4) {  const c = document.createElement('canvas');  c.width = ancho * factor;  c.height = alto * factor;  const ctx = c.getContext('2d');  ctx.scale(factor, factor);  dibujarEscena(ctx);           // la misma funcion, en unidades logicas  return c.toDataURL('image/png');}const img = new Image();img.src = exportarParaImprimir(dibujarEscena, 600, 300, 4);img.className = 'solo-impresion';document.body.appendChild(img);

Ese patrón solo es posible si tu función de dibujo trabaja en unidades lógicas y recibe el contexto como parámetro. Es un argumento de diseño más para separar la escena del dispositivo.

El segundo camino es generar un SVG a partir del mismo modelo de escena. Cuesta más, pero da un resultado independiente de la resolución y además abre la puerta a la exportación a PDF.

Edición posterior: qué queda cuando el proyecto envejece

La tercera consecuencia es la menos visible y la que más dinero cuesta a lo largo del tiempo: ¿qué se puede modificar dentro de un año?

De un vector se puede modificar todo: mover un punto, cambiar un color, escalar una parte, sustituir una fuente, exportar a otro formato. La descripción sigue ahí.

De un raster no se puede modificar casi nada sin degradarlo. Cambiar un color plano exige seleccionar la región y rellenar, lo que deja bordes sucios por el antialiasing. Cambiar el tamaño degrada. Cambiar un texto es imposible sin rehacer la zona.

En el canvas esa pregunta se traduce en una decisión de arquitectura muy concreta: ¿guardas el modelo de la escena o solo el resultado?

JS
// Malo: el estado esta en los pixeles y no hay vuelta atrasctx.fillStyle = '#89b4fa';ctx.fillRect(x, y, w, h);// Bien: el estado esta en datos, el canvas es solo la proyeccionconst escena = [{ tipo: 'rect', x, y, w, h, color: '#89b4fa' }];function pintar(ctx, escena) {  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);  for (const f of escena) {    ctx.fillStyle = f.color;    if (f.tipo === 'rect') ctx.fillRect(f.x, f.y, f.w, f.h);  }}

La versión de abajo cuesta diez líneas más y te da, de golpe: deshacer y rehacer, serialización a JSON, exportación a SVG, hit testing exacto, redibujado a cualquier resolución, tests unitarios sobre la escena sin necesidad de un navegador, y la posibilidad de cambiar el motor de dibujo sin tocar la lógica.

La versión de arriba te da un fichero PNG.

Qué guardar

De las tres consecuencias sale una única regla de proyecto: guarda siempre la representación de nivel más alto que tengas, y genera las demás desde ella.

Si el gráfico nace de datos, guarda los datos. Si nace de una descripción geométrica, guarda la descripción. Si nace de un programa de dibujo, guarda el fichero del programa además del exportado. El raster es siempre el último eslabón, el que se puede regenerar y el que nunca hay que tratar como fuente.

Aplicado al canvas, eso significa que el búfer de píxeles es un artefacto de salida, no el estado de tu aplicación. Cuando el búfer es el estado, has creado un producto que solo se puede mirar.