W3docs

Introdução ao Canvas

Aprenda o elemento HTML <canvas>: sistema de coordenadas, contexto de renderização 2D, escalonamento para alta resolução, acessibilidade e exemplos de desenho.

O elemento HTML <canvas> é uma superfície de desenho retangular controlada inteiramente por script. O elemento em si é apenas um contêiner vazio — ele não desenha nada por conta própria. Você usa JavaScript para emitir comandos de desenho que pintam pixels nele.

Esta página apresenta o elemento <canvas>, seu sistema de coordenadas, o contexto de renderização 2D e as operações de desenho mais comuns: formas, texto, gradientes, linhas e imagens.

O que é o elemento <canvas>?

<canvas> fornece um bitmap — uma grade de pixels na qual você desenha imediatamente. Após uma forma ser pintada, o canvas não a memoriza como objeto; ela passa a ser apenas pixels coloridos. Essa é a diferença fundamental em relação ao SVG, onde cada forma permanece como um nó DOM que pode ser reestilizado ou animado individualmente.

Essa diferença orienta quando usar o canvas:

  • Use <canvas> para controle no nível de pixel, muitos milhares de objetos, animação quadro a quadro rápida, jogos, processamento de imagens, gráficos com grande volume de dados ou efeitos de partículas. Por ser "modo imediato", redesenhar é barato.
  • Use SVG quando você precisar de vetores independentes de resolução, ícones escaláveis, um número gerenciável de formas que deseja inspecionar, clicar ou animar via CSS/DOM.
  • Use CSS para layout, transições e efeitos em elementos HTML comuns — não para desenho livre.
Dica

Você pode colocar mais de um elemento <canvas> na mesma página HTML, cada um com seu próprio contexto.

O sistema de coordenadas

Um canvas utiliza uma grade de coordenadas 2D. A origem (0, 0) é o canto superior esquerdo. O eixo x cresce para a direita e o eixo y cresce para baixo — note que y aumenta para baixo, o oposto de um gráfico matemático. Um ponto (100, 60) está, portanto, 100 pixels a partir da borda esquerda e 60 pixels a partir do topo.

A área de desenho é definida pelos atributos width e height (em pixels CSS):

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

Defina o tamanho do canvas com os atributos width e height, não com CSS. O width/height do CSS apenas estica o bitmap existente, o que desfoca seu desenho. Adicione uma borda com o atributo style ou uma classe.

O contexto de renderização 2D

Você nunca desenha diretamente no elemento <canvas> — você desenha por meio de um contexto de renderização, um objeto que expõe a API de desenho. Você o obtém com getContext():

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

getContext('2d') retorna um CanvasRenderingContext2D, que contém todos os métodos e propriedades utilizados abaixo (fillRect, arc, fillText, strokeStyle, entre outros). É o ponto de partida correto para quase todo desenho 2D.

Existem outros tipos de contexto para diferentes necessidades:

  • 'webgl' / 'webgl2' — 3D acelerado por GPU (e 2D de alto desempenho) via API OpenGL ES.
  • 'bitmaprenderer' — exibe um ImageBitmap sem API de desenho própria.

Este capítulo usa apenas o contexto '2d'.

Acessibilidade: conteúdo de fallback

Qualquer coisa colocada entre as tags de abertura e fechamento do <canvas> é conteúdo de fallback. Navegadores que suportam canvas o ignoram; navegadores (ou tecnologias assistivas) que não conseguem renderizar o canvas o exibem no lugar. Como os pixels desenhados são invisíveis para leitores de tela, use esse espaço para descrever o gráfico ou adicione um aria-label / role para que o canvas seja 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 interativos (jogos, aplicativos de desenho), forneça controles HTML focalizáveis reais dentro do elemento como fallback, já que os pixels em si não podem ser navegados por teclado.

Exemplo da tag 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>

Exemplo da tag HTML <canvas> para desenhar um 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>

O método arc() recebe cinco argumentos: arc(x, y, radius, startAngle, endAngle). Aqui (100, 100) é o centro do círculo, 60 é o raio em pixels, e o arco varre do ângulo 0 até 2 * Math.PI. Os ângulos são medidos em radianos, e um círculo completo equivale a radianos, portanto 0 a 2 * Math.PI desenha o círculo inteiro. beginPath() inicia um novo caminho e stroke() o contorna usando o strokeStyle atual. Para preenchê-lo, defina fillStyle e chame fill(). Saiba mais em Desenho no Canvas e Coordenadas do Canvas.

Exemplo da tag HTML <canvas> para desenhar um 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 preenchido nas coordenadas fornecidas. A propriedade font usa a abreviação de fonte padrão do CSS. Consulte Texto no Canvas para alinhamento, contorno de texto e medição de largura.

Exemplo da tag HTML <canvas> para desenhar um gradiente linear:

<!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 a direção do gradiente por dois pontos. Aqui (0, 0) a (300, 0) é um gradiente horizontal da esquerda para a direita. addColorStop(offset, color) posiciona uma cor de 0 (início) a 1 (fim), fazendo o verde desaparecer gradualmente até o branco. Atribuir o gradiente ao fillStyle faz com que fillRect(x, y, width, height) pinte com ele. Veja mais em Gradientes no Canvas.

Exemplo da tag HTML <canvas> para desenhar uma linha:

<!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 a "caneta" até um ponto inicial sem desenhar, e lineTo(x, y) adiciona um segmento reto até esse ponto. Nada aparece até que você chame stroke(). Consulte Desenho no Canvas para caminhos com múltiplos segmentos, espessura de linha e junções.

Exemplo da tag HTML <canvas> para desenhar uma imagem:

Para manter o exemplo autocontido (e evitar problemas de origem cruzada — veja a nota abaixo), este exemplo usa uma pequena imagem SVG inline como data URI em vez de uma 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() aceita três formas: drawImage(image, dx, dy), drawImage(image, dx, dy, dWidth, dHeight) para escalar, e drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) para recortar um retângulo de origem (s*) e posicioná-lo em um retângulo de destino (d*). Sempre desenhe dentro do evento load da imagem para garantir que os pixels estejam prontos. Consulte Imagens no Canvas para mais detalhes.

Perigo

Problema com CORS. Desenhar uma imagem de outra origem sem os cabeçalhos CORS adequados "contamina" o canvas. Após isso, getImageData() e toDataURL() lançam um erro de segurança. Se você precisar ler pixels de uma imagem remota, a imagem deve ser servida com cabeçalhos CORS permissivos e carregada com image.crossOrigin = "anonymous" antes de definir src.

Exemplo da tag HTML <canvas> para desenhar um gradiente 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) faz a transição entre dois círculos: um círculo inicial (centro (150, 75), raio 10) e um círculo final (centro (115, 90), raio 150). As paradas de cor vão do roxo no círculo interno ao branco no externo, produzindo o brilho redondo. Compare com createLinearGradient acima e leia mais em Gradientes no Canvas.

Telas de alta resolução (Retina)

Em telas de alta densidade, um pixel CSS corresponde a vários pixels do dispositivo. Um canvas dimensionado apenas em pixels CSS fica borrado nessas telas. A solução é escalar o bitmap por window.devicePixelRatio e, em seguida, escalar o contexto para que suas coordenadas de desenho permaneçam as mesmas:

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);

Após isso, desenhar arc(100, 100, 60, …) produz um círculo nítido tanto em telas padrão quanto em telas Retina.

Capítulos relacionados

Prática

Prática
Quais são as características e o uso do HTML Canvas?
Quais são as características e o uso do HTML Canvas?
Was this page helpful?