W3docs

Coordenadas do Canvas

Nesta página, você encontra informações úteis sobre as coordenadas do canvas HTML, além de exemplos de código para desenhar um círculo e uma linha.

O canvas HTML é um elemento poderoso do HTML5 que permite criar e manipular gráficos em uma página web usando JavaScript. O elemento <canvas> fornece uma superfície de desenho bidimensional que pode ser imaginada como uma grade ou sistema de coordenadas.

Esta página explica como funciona o sistema de coordenadas do canvas, como ler e definir pontos nele, e como mover, dimensionar e rotacionar esse sistema com transformações. Se você ainda não conhece o elemento em si, comece pela introdução ao Canvas.

O Sistema de Coordenadas

A grade do canvas começa no canto superior esquerdo, que tem as coordenadas (0, 0). A partir daí:

  • O eixo x aumenta para a direita.
  • O eixo y aumenta para baixo (o oposto do que a maioria das pessoas aprendeu nas aulas de matemática, onde y cresce para cima).

Cada ponto no canvas é um par (x, y) medido em pixels a partir dessa origem no canto superior esquerdo.

(0,0)──────── x increases → ────────►
  │  ┌───────────────────────────────┐
  │  │ (0,0)                  (300,0) │
  y  │                               │
  │  │            (150,75)           │
  ▼  │                               │
     │ (0,150)              (300,150)│
     └───────────────────────────────┘

Para um canvas de 300 × 150, (0, 0) é o canto superior esquerdo, (300, 0) é o canto superior direito, (0, 150) é o canto inferior esquerdo e (150, 75) é o centro exato.

O contexto de renderização 2D

Você nunca desenha diretamente no elemento <canvas>. Em vez disso, você solicita um contexto de renderização — um objeto que expõe os métodos de desenho (moveTo, lineTo, arc, fillRect, entre outros):

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

getContext("2d") retorna o contexto 2D usado em todos os exemplos abaixo. (Existem outros tipos de contexto, como "webgl" para 3D, mas "2d" é o usado para desenho no canvas.) Cada coordenada passada a um método do contexto é interpretada na grade descrita acima.

Desenhando uma Linha

Os métodos abaixo são usados para desenhar uma linha reta em um canvas:

  • moveTo(x,y), que especifica o ponto de início da linha
  • lineTo(x,y), que especifica o ponto final da linha

Use um dos métodos de "tinta" para desenhar a linha, por exemplo, stroke().

Exemplo do elemento HTML <canvas> para desenhar uma linha:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas width="300" height="150" style="border:1px solid #cccccc;" id="canvasExample">
      Your browser does not support the HTML5 canvas tag.
    </canvas>
    <script>
      const c = document.getElementById("canvasExample");
      const ctx = c.getContext("2d");
      // Starting point (0,0) is the top-left corner
      ctx.moveTo(0, 0);
      // Ending point (300,150) matches the canvas width and height
      ctx.lineTo(300, 150);
      ctx.strokeStyle = '#359900';
      ctx.stroke();
    </script>
  </body>
</html>

No exemplo acima, a linha é desenhada na diagonal de (0, 0) (canto superior esquerdo) até (300, 150) (canto inferior direito). Observe que essa única linha não precisou de beginPath(): quando nada mais foi desenhado ainda, moveTo/lineTo iniciam um novo caminho automaticamente. O círculo abaixo usa beginPath() porque é uma forma separada — veja a explicação nessa seção.

Para mais formas e preenchimentos construídos no mesmo sistema de coordenadas, consulte Desenho no Canvas.

Desenhando um Círculo

Os métodos abaixo são usados para desenhar um círculo em um canvas:

  • beginPath(), que inicia um novo caminho para que o círculo não se conecte a nada desenhado anteriormente.
  • arc(x, y, r, startAngle, endAngle), que adiciona um arco (uma porção de círculo) ao caminho atual.

Os parâmetros de arc()

ParâmetroSignificado
x, yAs coordenadas do centro do círculo.
rO raio, em pixels.
startAngleOnde o arco começa, em radianos.
endAngleOnde o arco termina, em radianos.

Os ângulos são medidos em radianos, não em graus, e 0 aponta para a direita (o eixo x positivo), girando no sentido horário. Uma volta completa é 2 * Math.PI radianos (360°), portanto um círculo completo vai de 0 a 2 * Math.PI.

Para converter graus em radianos, multiplique por Math.PI / 180:

const radians = degrees * (Math.PI / 180);

Arcos parciais

Não é necessário desenhar um círculo completo. Use um ângulo final menor para desenhar apenas parte de um. Por exemplo, um arco de 0 a Math.PI (meia volta completa) desenha a metade inferior de um círculo, pois y aumenta para baixo:

// A half-circle (bottom half) centered at (100, 75) with radius 50
ctx.beginPath();
ctx.arc(100, 75, 50, 0, Math.PI);
ctx.stroke();

Exemplo do elemento HTML <canvas> para desenhar um círculo:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="exampleCanvas" width="250" height="200" style="border:1px solid #dddddd;">
      The canvas tag is not supported by your browser.
    </canvas>
    <script>
      const canvas = document.getElementById("exampleCanvas");
      const ctx = canvas.getContext("2d");
      ctx.beginPath();
      // Center at (125, 95), radius 70. 125 is half of the 250 width.
      ctx.arc(125, 95, 70, 0, 2 * Math.PI);
      ctx.strokeStyle = '#1c87c9';
      ctx.closePath();
      ctx.stroke();
    </script>
  </body>
</html>

No exemplo acima, o círculo está centralizado em (125, 95) com um raio de 70.

beginPath() e closePath()

Esses dois métodos frequentemente causam confusão:

  • beginPath() descarta qualquer caminho que estava sendo construído e inicia um completamente novo. Chame-o antes de cada forma independente — caso contrário, a nova forma é unida à anterior, e um único stroke()/fill() estiliza todas juntas.
  • closePath() desenha uma linha reta do ponto atual de volta ao início do caminho, "fechando" o contorno. Para um círculo completo, o final já encontra o início, portanto closePath() não tem efeito visível aqui — é incluído como bom hábito e importa quando você constrói formas abertas como um polígono.

O exemplo da linha anterior não precisou de nenhum dos dois métodos porque era um caminho único e independente. Assim que você desenhar uma segunda forma, recorra ao beginPath().

Transformações de Coordenadas

Em vez de recalcular cada coordenada manualmente, você pode mover, redimensionar ou rotacionar o sistema de coordenadas inteiro. As transformações afetam tudo que você desenhar depois de chamá-las.

Um padrão comum é envolver o desenho transformado com save() e restore() para que a grade retorne ao normal em seguida:

ctx.save();      // remember the current coordinate system
// ...transform and draw...
ctx.restore();   // put the coordinate system back

translate(x, y)

Move a origem (0, 0) para uma nova posição. Após translate(50, 30), desenhar em (0, 0) aparece de fato em (50, 30):

ctx.translate(50, 30);
ctx.fillRect(0, 0, 80, 40); // top-left corner now sits at (50, 30)

scale(x, y)

Multiplica o tamanho de cada coordenada e dimensão. scale(2, 2) dobra o tamanho de tudo; scale(1, 0.5) mantém a largura mas reduz a altura pela metade:

ctx.scale(2, 2);
ctx.fillRect(10, 10, 30, 30); // drawn at (20, 20), 60×60 in real pixels

rotate(angle)

Rotaciona o sistema de coordenadas no sentido horário em torno da origem atual. O ângulo é em radianos, assim como em arc(). Como a rotação acontece em torno de (0, 0), normalmente você usa translate() para ir até o ponto de pivô primeiro:

ctx.translate(100, 75);          // move origin to the pivot point
ctx.rotate(45 * Math.PI / 180);  // rotate 45° clockwise
ctx.fillRect(-25, -25, 50, 50);  // a square centered on the pivot

As transformações mantêm suas coordenadas na mesma grade que você vinha usando — elas apenas reposicionam ou reformatam essa grade. Para desenhar texto posicionado nesse sistema, consulte Texto no Canvas.

Prática

Prática
Quais são as características das coordenadas do elemento <canvas> do HTML5?
Quais são as características das coordenadas do elemento <canvas> do HTML5?
Was this page helpful?