W3docs

Introducción a Canvas

Aprende el elemento HTML <canvas>: sistema de coordenadas, contexto 2D, escalado HiDPI, accesibilidad y ejemplos de dibujo ejecutables.

El elemento HTML <canvas> es una superficie de dibujo rectangular que controlas completamente desde un script. El elemento en sí es solo un contenedor vacío — no dibuja nada por sí solo. Utilizas JavaScript para emitir comandos de dibujo que pintan píxeles sobre él.

Esta página presenta el elemento <canvas>, su sistema de coordenadas, el contexto de renderizado 2D y las operaciones de dibujo más comunes: formas, texto, degradados, líneas e imágenes.

¿Qué es el elemento <canvas>?

<canvas> te proporciona un mapa de bits — una cuadrícula de píxeles en la que dibujas de forma inmediata. Una vez que se pinta una forma, el canvas no la recuerda como un objeto; son simplemente píxeles con color. Esta es la diferencia clave respecto a SVG, donde cada forma permanece como un nodo del DOM que puedes reestilizar o animar individualmente.

Esta diferencia guía cuándo usar canvas:

  • Elige <canvas> para control a nivel de píxeles, miles de objetos, animación fotograma a fotograma rápida, juegos, procesamiento de imágenes, gráficos con muchos datos o efectos de partículas. Al ser de "modo inmediato", redibujar es barato.
  • Elige SVG cuando necesites vectores independientes de la resolución, iconos escalables, un número manejable de formas que quieras inspeccionar, pulsar o animar mediante CSS/DOM.
  • Elige CSS para diseño, transiciones y efectos sobre elementos HTML normales — no para dibujo libre.
Consejo

Puedes colocar más de un elemento <canvas> en la misma página HTML, cada uno con su propio contexto.

El sistema de coordenadas

Un canvas usa una cuadrícula de coordenadas 2D. El origen (0, 0) es la esquina superior izquierda. El eje x aumenta hacia la derecha y el eje y aumenta hacia abajo — ten en cuenta que y crece hacia abajo, lo contrario que en una gráfica matemática. Un punto (100, 60) está por tanto a 100 píxeles del borde izquierdo y 60 píxeles desde la parte superior.

El área de dibujo se define mediante los atributos width y height (en píxeles CSS):

<canvas id="canvas" width="250" height="150"></canvas>
Peligro

Establece el tamaño del canvas con los atributos width y height, no con CSS. width/height en CSS solo estiran el mapa de bits existente, lo que desenfoca el dibujo. Añade un borde con el atributo style o una clase.

El contexto de renderizado 2D

Nunca dibujas directamente sobre el elemento <canvas> — dibujas a través de un contexto de renderizado, un objeto que expone la API de dibujo. Lo obtienes con getContext():

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

getContext('2d') devuelve un CanvasRenderingContext2D, que contiene todos los métodos y propiedades que se usan a continuación (fillRect, arc, fillText, strokeStyle, etc.). Es el punto de partida adecuado para casi todo el dibujo 2D.

Existen otros tipos de contexto para distintas necesidades:

  • 'webgl' / 'webgl2' — 3D acelerado por GPU (y 2D de alto rendimiento) mediante la API OpenGL ES.
  • 'bitmaprenderer' — muestra un ImageBitmap sin API de dibujo propia.

Este capítulo usa únicamente el contexto '2d'.

Accesibilidad: contenido alternativo

Todo lo que coloques entre las etiquetas de apertura y cierre de <canvas> es contenido alternativo. Los navegadores que admiten canvas lo ignoran; los navegadores (o tecnologías de asistencia) que no pueden renderizar el canvas lo muestran en su lugar. Dado que los píxeles dibujados son invisibles para los lectores de pantalla, usa este espacio para describir el gráfico, o añade un aria-label / role para que el canvas sea anunciado de forma significativa.

<canvas id="canvas" width="250" height="150" role="img" aria-label="A blue circle on a white background">
  A blue circle on a white background.
</canvas>

Para canvases interactivos (juegos, aplicaciones de dibujo), proporciona controles HTML reales con foco dentro del elemento como alternativa, ya que los píxeles en sí no pueden recibir el foco mediante el teclado.

Ejemplo de la etiqueta HTML <canvas>:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="canvas" width="250" height="150" style="border:1px solid #1c87c9;">
      The HTML5 canvas tag is not supported by your browser.
    </canvas>
  </body>
</html>

Ejemplo de la etiqueta HTML <canvas> para dibujar un círculo:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="exampleCanvas" width="200" height="200" style="border:1px solid #dddddd;">
      HTML5 canvas tag is not supported by your browser.
    </canvas>
    <script>
      const c = document.getElementById("exampleCanvas");
      const ctx = c.getContext("2d");
      ctx.beginPath();
      ctx.arc(100, 100, 60, 0, 2 * Math.PI);
      ctx.strokeStyle = '#009299';
      ctx.stroke();
    </script>
  </body>
</html>

El método arc() recibe cinco argumentos: arc(x, y, radius, startAngle, endAngle). Aquí (100, 100) es el centro del círculo, 60 es el radio en píxeles, y el arco barre desde el ángulo 0 hasta 2 * Math.PI. Los ángulos se miden en radianes, y un círculo completo equivale a radianes, por lo que de 0 a 2 * Math.PI se dibuja el círculo completo. beginPath() inicia un trazado nuevo, y stroke() lo contornea usando el strokeStyle actual. Para rellenarlo, establece fillStyle y llama a fill(). Aprende más en Dibujo en Canvas y Coordenadas de Canvas.

Ejemplo de la etiqueta HTML <canvas> para dibujar texto:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="exampleCanvas" width="350" height="110" style="border:1px solid #dddddd;">
      HTML5 canvas tag is not supported by your browser.
    </canvas>
    <script>
      const c = document.getElementById("exampleCanvas");
      const ctx = c.getContext("2d");
      ctx.font = "40px Arial";
      ctx.fillStyle = '#262ac7';
      ctx.fillText("Canvas Text", 55, 65);
    </script>
  </body>
</html>

fillText(text, x, y) pinta texto relleno en las coordenadas indicadas. La propiedad font utiliza la sintaxis abreviada de fuentes de CSS. Consulta Texto en Canvas para alineación, contorno de texto y medición del ancho.

Ejemplo de la etiqueta HTML <canvas> para dibujar un degradado lineal:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="exampleCanvas" width="300" height="140" style="border:1px solid #dddddd;">
      The HTML5 canvas tag is not supported by your browser.
    </canvas>
    <script>
      const c = document.getElementById("exampleCanvas");
      const ctx = c.getContext("2d");
      const grd = ctx.createLinearGradient(0, 0, 300, 0);
      grd.addColorStop(0, "#359900");
      grd.addColorStop(1, "#ffffff");
      ctx.fillStyle = grd;
      ctx.fillRect(20, 20, 250, 100);
    </script>
  </body>
</html>

createLinearGradient(x0, y0, x1, y1) define la dirección del degradado mediante dos puntos. Aquí de (0, 0) a (300, 0) es un degradado horizontal de izquierda a derecha. addColorStop(offset, color) coloca un color en una posición de 0 (inicio) a 1 (fin), de modo que el verde se desvanece hasta blanco. Asignar el degradado a fillStyle hace que fillRect(x, y, width, height) pinte con él. Más información en Degradados de Canvas.

Ejemplo de la etiqueta HTML <canvas> para dibujar una línea:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="exampleCanvas" width="150" height="150" style="border:1px solid #cccccc;">
      The HTML5 canvas tag is not supported by your browser.
    </canvas>
    <script>
      const c = document.getElementById("exampleCanvas");
      const ctx = c.getContext("2d");
      ctx.moveTo(0, 0);
      ctx.lineTo(150, 150);
      ctx.strokeStyle = '#86417d';
      ctx.stroke();
    </script>
  </body>
</html>

moveTo(x, y) levanta el "lápiz" hasta un punto de inicio sin dibujar, y lineTo(x, y) añade un segmento recto hasta ese punto. No aparece nada hasta que llamas a stroke(). Consulta Dibujo en Canvas para trazados con varios segmentos, grosor de línea y uniones.

Ejemplo de la etiqueta HTML <canvas> para dibujar una imagen:

Para mantenerse independiente (y evitar problemas de origen cruzado — ver la nota a continuación), este ejemplo usa una pequeña imagen SVG en línea como URI de datos en lugar de una foto remota:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <h2>Draw an image with canvas</h2>
    <canvas id="exampleCanvas" width="220" height="120" style="border:1px solid #dddddd;"></canvas>
    <script>
      const canvas = document.getElementById('exampleCanvas');
      const ctx = canvas.getContext('2d');
      const image = new Image();
      image.addEventListener('load', () => {
        // drawImage(image, dx, dy) draws at the given top-left position
        ctx.drawImage(image, 10, 10);
        // Scaled copy: drawImage(image, dx, dy, dWidth, dHeight)
        ctx.drawImage(image, 120, 10, 50, 50);
      });
      image.src =
        "data:image/svg+xml," +
        encodeURIComponent(
          '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">' +
          '<circle cx="50" cy="50" r="45" fill="#1c87c9" /></svg>'
        );
    </script>
  </body>
</html>

drawImage() acepta tres formas: drawImage(image, dx, dy), drawImage(image, dx, dy, dWidth, dHeight) para escalar, y drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) para recortar un rectángulo fuente (s*) y colocarlo en un rectángulo destino (d*). Dibuja siempre dentro del evento load de la imagen para que los píxeles estén listos. Consulta Imágenes en Canvas para más información.

Peligro

Problema con CORS. Dibujar una imagen de otro origen sin las cabeceras CORS adecuadas "contamina" el canvas. Después de eso, getImageData() y toDataURL() lanzan un error de seguridad. Si necesitas leer píxeles de una imagen remota, la imagen debe servirse con cabeceras CORS permisivas y cargarse con image.crossOrigin = "anonymous" antes de establecer src.

Ejemplo de la etiqueta HTML <canvas> para dibujar un degradado circular:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="exampleCanvas" width="260" height="160" style="border:1px solid #cdcdcd;">
      The HTML5 canvas tag is not supported by your browser.
    </canvas>
    <script>
      const c = document.getElementById("exampleCanvas");
      const ctx = c.getContext("2d");
      const grd = ctx.createRadialGradient(150, 75, 10, 115, 90, 150);
      grd.addColorStop(0, "purple");
      grd.addColorStop(1, "white");
      ctx.fillStyle = grd;
      ctx.fillRect(20, 20, 220, 120);
    </script>
  </body>
</html>

createRadialGradient(x0, y0, r0, x1, y1, r1) mezcla entre dos círculos: un círculo inicial (centro (150, 75), radio 10) y un círculo final (centro (115, 90), radio 150). Los puntos de color se desvanecen desde morado en el círculo interior hasta blanco en el exterior, produciendo el brillo circular. Compara con createLinearGradient anterior y lee más en Degradados de Canvas.

Pantallas de alta densidad (Retina)

En pantallas de alta densidad, un píxel CSS se corresponde con varios píxeles de dispositivo. Un canvas dimensionado solo en píxeles CSS aparecerá borroso en esas pantallas. La solución es escalar el mapa de bits por window.devicePixelRatio y luego escalar el contexto para que las coordenadas de dibujo permanezcan iguales:

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const ratio = window.devicePixelRatio || 1;

// CSS size (layout) stays the same:
const cssWidth = 250;
const cssHeight = 150;
canvas.style.width = cssWidth + 'px';
canvas.style.height = cssHeight + 'px';

// Backing bitmap gets more device pixels:
canvas.width = cssWidth * ratio;
canvas.height = cssHeight * ratio;

// Scale once so you keep drawing in CSS-pixel coordinates:
ctx.scale(ratio, ratio);

Tras esto, dibujar arc(100, 100, 60, …) produce un círculo nítido tanto en pantallas estándar como Retina.

Capítulos relacionados

Práctica

Práctica
¿Cuáles son las características y el uso de HTML Canvas?
¿Cuáles son las características y el uso de HTML Canvas?
Was this page helpful?