Desenhando no Canvas
Aprenda a desenhar no canvas HTML com JavaScript passo a passo: retângulos, contornos, caminhos, linhas, círculos e arcos, com exemplos de código executáveis.
O elemento <canvas> é apenas uma superfície de desenho em branco e transparente. Por si só, ele não exibe nada — não é possível desenhar nele com HTML ou CSS. Todo desenho em um canvas é feito com JavaScript, por meio de um objeto chamado contexto de renderização. Esta página percorre as operações de desenho 2D essenciais passo a passo: preenchimento de retângulos, traçado de contornos, desenho de caminhos livres e desenho de círculos e arcos.
Se você ainda não criou um elemento <canvas>, comece pela tag HTML <canvas> e pela introdução ao Canvas.
O sistema de coordenadas do canvas
Todo método de desenho utiliza coordenadas em pixels. A grade do canvas tem sua origem (0, 0) no canto superior esquerdo. O eixo x cresce para a direita e o eixo y cresce para baixo (observe que y aumenta ao se mover para baixo, ao contrário de um gráfico matemático). Portanto, o ponto (0, 0) é o pixel superior esquerdo, e (width, height) é o canto inferior direito.
Para uma análise mais detalhada da grade, veja Coordenadas do Canvas.
1. Encontre o elemento canvas
Primeiro, obtenha uma referência ao elemento <canvas> no DOM com getElementById():
const canvas = document.getElementById("canvas");2. Obtenha o contexto de renderização 2D
Chame o método getContext() para obter um contexto de desenho. Passar "2d" retorna um objeto CanvasRenderingContext2D, que contém todas as propriedades e métodos usados para desenhar:
const ctx = canvas.getContext("2d");A variável ctx (abreviação de "context") é onde você chama todos os comandos de desenho.
getContext() retorna null se o navegador não puder fornecer o contexto solicitado (por exemplo, se "2d" estiver escrito incorretamente, ou se o elemento não for um <canvas> de fato). É uma boa prática se proteger contra isso antes de desenhar, para que um contexto ausente falhe silenciosamente em vez de lançar um erro na linha seguinte:
const ctx = canvas.getContext("2d");
if (!ctx) return; // bail out if the 2D context is unavailable; only valid inside a functionEm um <script> inline simples (que não é o corpo de uma função), envolva o desenho em if (ctx) { ... }, como fazem os exemplos abaixo.
3. Desenhe um retângulo preenchido
A propriedade fillStyle define a cor usada para preencher formas. Pode ser qualquer cor CSS, um padrão ou um gradiente:
ctx.fillStyle = "#1c87c9";Em seguida, fillRect(x, y, width, height) desenha um retângulo preenchido. Os dois primeiros parâmetros são as coordenadas x e y do canto superior esquerdo, seguidas pela largura e altura em pixels:
ctx.fillRect(0, 0, 230, 130);Exemplo de desenho de um retângulo preenchido:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<canvas id="canvas" width="250" height="150" role="img"
aria-label="A blue filled rectangle" style="border:1px solid #dddddd;">
Your browser does not support the canvas element.
</canvas>
<script>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
if (ctx) {
// only draw when the 2D context is available
ctx.fillStyle = "#1c87c9";
ctx.fillRect(0, 0, 230, 130);
}
</script>
</body>
</html>Torne o canvas acessível
Tudo o que você desenha em um canvas são apenas pixels — ele não possui estrutura, portanto leitores de tela não conseguem vê-lo. Não há nada a anunciar, e usuários de teclado não podem acessar nada dentro dele. Forneça à tecnologia assistiva um equivalente textual de duas formas:
- Conteúdo de fallback fica entre as tags
<canvas>. Navegadores que renderizam o canvas o ignoram; a tecnologia assistiva (e navegadores muito antigos) o utiliza em seu lugar. Coloque uma descrição significativa aqui, não "seu navegador não suporta canvas." role="img"maisaria-labeldescreve o desenho finalizado como uma única imagem, da mesma forma que o textoaltdescreve um<img>.
<canvas id="chart" width="250" height="150" role="img"
aria-label="Bar chart: sales doubled from Q1 to Q2.">
A bar chart showing sales doubling from Q1 to Q2.
</canvas>Para qualquer elemento interativo (regiões clicáveis, controles), forneça também elementos DOM reais e focalizáveis — canvas sozinho não é acessível pelo teclado.
Contorno, sem preenchimento
Às vezes você quer apenas o contorno de uma forma, em vez de um preenchimento sólido. Use a propriedade strokeStyle para definir a cor do contorno e strokeRect(x, y, width, height) para desenhar um retângulo sem preenchimento. A propriedade lineWidth controla a espessura do contorno:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<canvas id="canvas" width="250" height="150" role="img"
aria-label="A blue rectangular outline" style="border:1px solid #dddddd;">
A rectangle drawn as an outline.
</canvas>
<script>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
if (ctx) {
ctx.strokeStyle = "#1c87c9";
ctx.lineWidth = 4;
ctx.strokeRect(20, 20, 200, 100);
}
</script>
</body>
</html>Limpando parte do canvas
clearRect(x, y, width, height) apaga o retângulo especificado, tornando-o totalmente transparente novamente. É comumente usado para limpar todo o canvas antes de redesenhar (por exemplo, a cada quadro de uma animação):
// Erase everything on a 250 × 150 canvas
ctx.clearRect(0, 0, 250, 150);No próximo exemplo, dois retângulos azuis são desenhados e, em seguida, clearRect() abre um buraco transparente no meio do canvas — observe que o retângulo da direita está parcialmente apagado:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<canvas id="canvas" width="250" height="150" role="img"
aria-label="Two blue squares with a cleared rectangle cut out of the middle"
style="border:1px solid #dddddd;">
Two filled squares with a cleared region.
</canvas>
<script>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
if (ctx) {
ctx.fillStyle = "#1c87c9";
ctx.fillRect(20, 20, 100, 100);
ctx.fillRect(130, 20, 100, 100);
ctx.clearRect(90, 50, 70, 50); // erase a rectangle across both
}
</script>
</body>
</html>Desenhando caminhos (linhas e formas personalizadas)
Retângulos são convenientes, mas a maioria dos desenhos usa caminhos — sequências de pontos conectados por linhas ou curvas. Um caminho é construído com um pequeno conjunto de métodos e só fica visível quando você chama stroke() (para desenhar o contorno) ou fill() (para preencher a área delimitada).
| Método | O que faz |
|---|---|
beginPath() | Inicia um novo caminho vazio. |
moveTo(x, y) | Move a "caneta" para (x, y) sem desenhar. |
lineTo(x, y) | Adiciona uma linha reta do ponto atual até (x, y). |
closePath() | Desenha uma linha de volta ao ponto inicial do caminho. |
stroke() | Renderiza o caminho como um contorno. |
fill() | Preenche a área delimitada pelo caminho. |
Sempre comece com beginPath()
beginPath() limpa a lista de pontos que o contexto está rastreando atualmente e inicia um caminho novo. Isso é importante porque o canvas lembra todos os sub-caminhos até que você o reinicie. Se você desenhar uma forma e depois começar a adicionar pontos para uma segunda forma sem chamar beginPath(), os pontos antigos ainda estão no caminho — portanto, o próximo stroke() ou fill() redesenha a primeira forma também, muitas vezes com a nova cor e espessura de linha. O resultado são formas "vazando" umas nas outras.
Regra de ouro: chame beginPath() antes de cada nova forma. Cada exemplo abaixo começa dessa forma.
Exemplo: uma linha simples
Para desenhar uma linha, inicie um caminho, mova-se para o ponto de início, desenhe uma linha até o ponto final e então trace-a:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<canvas id="canvas" width="250" height="150" role="img"
aria-label="A diagonal blue line" style="border:1px solid #dddddd;">
A diagonal line drawn across the canvas.
</canvas>
<script>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
if (ctx) {
ctx.beginPath();
ctx.moveTo(20, 20); // start point (x, y)
ctx.lineTo(220, 120); // end point (x, y)
ctx.lineWidth = 3;
ctx.strokeStyle = "#1c87c9";
ctx.stroke(); // make the line visible
}
</script>
</body>
</html>Exemplo: um triângulo
Encadear várias chamadas lineTo() cria uma forma com múltiplos lados. closePath() conecta o último ponto ao primeiro, e fill() preenche a área delimitada:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<canvas id="canvas" width="250" height="150" role="img"
aria-label="A filled green triangle" style="border:1px solid #dddddd;">
A filled green triangle.
</canvas>
<script>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
if (ctx) {
ctx.beginPath();
ctx.moveTo(125, 20); // top vertex
ctx.lineTo(220, 130); // bottom-right vertex
ctx.lineTo(30, 130); // bottom-left vertex
ctx.closePath(); // back to the top vertex
ctx.fillStyle = "#8ebf42";
ctx.fill();
}
</script>
</body>
</html>Desenhando círculos e arcos
O método arc() desenha círculos e segmentos curvos:
ctx.arc(x, y, radius, startAngle, endAngle, counterclockwise);x,y— as coordenadas do centro do arco.radius— o raio em pixels.startAngle,endAngle— os ângulos de início e fim em radianos (não graus). O ângulo0aponta ao longo do eixo x positivo — diretamente para a direita, a direção das 3 horas — e por padrão os ângulos aumentam no sentido horário (porque o eixo y do canvas cresce para baixo). Um círculo completo equivale a2 * Math.PIradianos.counterclockwise— um boolean opcional. Passetruepara percorrer no sentido oposto (padrão éfalse).
Como os ângulos estão em radianos, é conveniente converter a partir de graus com um pequeno auxiliar:
function toRadians(degrees) {
return degrees * Math.PI / 180;
}
// e.g. a quarter turn:
ctx.arc(125, 75, 50, 0, toRadians(90));Assim, 90 graus equivale a Math.PI / 2, 180 graus a Math.PI, e 360 graus a 2 * Math.PI.
Um círculo completo vai de 0 a 2 * Math.PI. Como em qualquer caminho, você deve chamar stroke() ou fill() para que ele apareça:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
<canvas id="canvas" width="250" height="150" role="img"
aria-label="A blue filled circle" style="border:1px solid #dddddd;">
A filled blue circle.
</canvas>
<script>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
if (ctx) {
ctx.beginPath();
ctx.arc(125, 75, 50, 0, 2 * Math.PI); // center (125,75), radius 50, full circle
ctx.fillStyle = "#1c87c9";
ctx.fill();
}
</script>
</body>
</html>Para desenhar meio círculo (uma semicírculo), encerre o arco em Math.PI radianos em vez de 2 * Math.PI.
O que explorar em seguida
Quando você estiver confortável com formas e caminhos, explore o restante do tutorial de Canvas:
- Coordenadas do Canvas — a grade em mais detalhes.
- Texto no Canvas — escrevendo texto com
fillText()estrokeText(). - Gradientes no Canvas — gradientes de cores lineares e radiais.
- Imagens no Canvas — desenhando imagens com
drawImage(). - Referência do Canvas — a lista completa de propriedades e métodos.