HTML 5 - Canvas


1. API de tela 2D

A API de tela 2D é um objeto que permite desenhar e manipular imagens e elementos gráficos em um elemento canvas. Antes de tudo deve-se entender que o HTML é uma linguagem de marcação, a lógica da programação começa na primeira linha e vai para linha seguinte, algumas tags não funcionam se colocadas por último em determinados códigos, é necessário fazer alguns testes de funcionamento.
Para fazer referência ao contexto da tela, você chama getContext, que é um método no elemento canvas. Ele tem um parâmetro, que atualmente é 2d. Aqui está o trecho de código para a referência ao contexto:
<!DOCTYPE html>
<html lang="pt_BR">
<head><title>Queda Livre</title>
<meta charset="utf-8">
</head>
<body>
<canvas id="canvas" height="100" width="100"></canvas>
<script>
var myCanvas = document.getElementById("myCanvas");
var ctx = myCanvas.getContext("2d");
</script>
</body>
</html>

Cada canvas tem seu próprio contexto, então, se a sua página contiver vários elementos canvas, você deve ter uma referência a cada contexto desse canvas individualmente.
O script também pode ser colocado dentro do cabeçalho, <head><script>...</script></head>, porém, a lógica da linguagem de macação é uma seqüência, alguns códigos não são executados com o script no cabeçalho, a seqüência é garantida com o script no corpo do código HTML:
<body>
<canvas id="canvas" height="100" width="100"></canvas>
<script>
var myCanvas = document.getElementById("myCanvas");
var ctx = myCanvas.getContext("2d");
</script>
</body>

Além de getContext, há muitas outras funções à sua disposição na API de tela 2D. Algumas das notáveis estão descritas abaixo.

2. Funções Padrão
Será apresentado algumas funções padronizadas do elemento canvas a título de recordação. Caso tenha dúvidas consulte outra fonte de pesquisa.
2.1. Funções de Transformações
scale: permite dimensionar o contexto atual.
rotate: permite a rotação das coordenadas x e y do contexto atual.

2.2. Funções de estado
save: permite salvar o estado atual do contexto
restore: permite restaurar o estado do contexto a partir de um estado salvo anteriormente.

2.2. Funções de texto
font: apanha ou define a fonte para o contexto atual.
fillText: renderiza texto preenchido na tela atual.
measureText: mede a largura atual do texto especificado.

2.3. Desenho no contexto do canvas
Formas e cores
Existe um grupo inteiro de propriedades e funções dedicadas a desenhar formas. Comecemos com retângulos. Aqui estão as funções relacionadas disponíveis para desenhar retângulos.
fillRect(x, y, w, h): desenha o retângulo definido na tela, usando o estilo de preenchimento atual
strokeRect(x, y, w, h): desenha a caixa de contorna o retângulo definido na tela, usando o traço atual
clearRect(x, y, w, h): limpa o retângulo definido pelos parâmetros.

2.4. Arcos
Utilizado para construção de circunferências, arcos e círculos.
arc()
arc(x, y, radius, startAngle, endAngle, anticlockwise)
Note: Angles in the arcfunction are measured in radians, not degrees. To convert degrees to radians you can use the following JavaScript expression: radians = (Math.PI/180)*degrees.

Example:
<!DOCTYPE html>
<html lang="pt_BR">
<head><title>Queda Livre</title>
<meta charset="utf-8">
<style>
canvas {
    display:block;
    margin:10px auto;
    border:1px solid #999;
}
</style>
</head>
<body>
<canvas id="canvas" height="100" width="100"></canvas>
<script>
//get a reference to the canvas
 var canvas = document.getElementById('canvas');
 ctx = canvas.getContext('2d');
//draw a circle
ctx.beginPath();
ctx.arc(75, 75, 10, 0, Math.PI*2, true);
ctx.arc(0, 0, 10, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
</script>
</body>
</html>
Resultado:

Exemplo:
Este exemplo converte o sistema de coordenadas da tela para o sistema de coordenadas cartesiano.

<!DOCTYPE html>
<html lang="pt_BR">
<head><title>Queda Livre</title>
<meta charset="utf-8">
<style>
canvas {
    display:block;
    margin:10px auto;
    border:1px solid #999;
}
</style>
</head>
<body>
<canvas id="canvas2" height="100" width="100"></canvas>
<script>
//get a reference to the canvas
 var canvas2 = document.getElementById('canvas2');
      ctx = canvas2.getContext('2d');
// eixo-x para baixo
ctx.translate(0,100);
// eixo-y positivo para cima
ctx.scale(1, -1); 
//draw a circle
ctx.beginPath();
ctx.arc(75, 75, 10, 0, Math.PI*2, true);
ctx.arc(0, 0, 10, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
</script>
</body>
</html>
Resultado:

3. JavaScript
Para trabalhar com o tempo em JavaScript utiliza-se as funções setTimeout() e setInterval().

3.1. Diferença entre as funções setTimeout() e setInterval()

A sintaxe das duas funções é praticamente idêntica. O que muda é como elas agem.
Sintaxe:
window.setTimeout('funcao()', intervalo_em_milisegundos);
window.setInterval('funcao()', intervalo_em_milisegundos);
Em ambas o primeiro parâmetro é uma função que será chamada pelo segundo parâmetro que é um interlado de tempo.
Sendo a setTimeout() chamando a função uma única vez. Enquanto a setInterval() chama a função “infinitamente” sempre no mesmo intervalo de tempo.
Para pausar a função usa-se clearInterval(). Passando como parâmetro o nome do seu intervalo.

Exemplo:
var intervalo = window.setInterval(function1, 1000);
function function1() {
    window.alert("Popup");
}
clearInterval(intervalo);

Exemplo:
Juntando as duas funções pode-se fazer, por exemplo, um script que simula um sorteio.
var intervalo = window.setInterval(function() {
    // corpo da funcao
}, 50);
window.setTimeout(function() {
    clearInterval(intervalo);
}, 3000);

Explicando: A setInterval() vai executar o que for definido dentro de uma função passada como parâmetro em 50 em 50 milisegundos. Isso durante 3000 milisegundos (3 segundos), que é o tempo definido na setTimeout() para entrar na função que pausa a setInterval.

4. Eixo de Coordenadas
Antes de iniciar com os estudos, deve-se adaptar o sistema de coordenadas da tela com o sistema de coordenadas cartesiano que é o sistema usualmente empregado na matemática e na física, isso se torna necessário principalmente para plotagem de gráficos e para facilitação do entendimento.
Pode-se trabalhar com o sistema de coordenadas da tela normalmente, o inconveniente é que toda teoria em matemática e física não usam o sistema de coordenadas com eixo-y positivo para baixo, há necessidade de adaptar a teoria.

Conversão para o Sistema de Coordenadas Cartesiano em HTML5
Para plotar uma função na tela deve-se converter a tela  para o sistema de coordenadas cartesiano, pois é com esse sistema que é utilizado em matemática, para isso deve-se inverter o sinal do eixo-y da tela ou canva e transladar todos os pontos deste eixo para cima do eixo x da tela ou canva.

4.1. Translação Vertical
Simplesmente soma-se um valor a f(x) para o mesmo x.
f(x) → a + f(x)
a > 0 para cima ↑
a < 0 para baixo ↓

4.2. Translação Horizontal
Não será utilizado neste exercício, está sendo apresentado para completar o assunto sobre translação.
x → x + a
a > 0 deslocamento do gráfico para a esquerda ←, isto significa que o eixo-x se deslocou para a direita e o gráfico ficou parado, com isso,  o gráfico fica à esquerda.

a < 0 deslocamento do gráfico para a direita → , isto significa que o eixo-x se deslocou para à esquerda e o gráfico ficou parado, com isso,  o gráfico fica à direita.

4.3. Transformação para o Sistema Cartesiano
Coordenadas de um monitor, uma Canva ou Tela.

4.3.1. Mudança de escala do eixo-y
O eixo-y da tela deve ser multiplicado por -1.

Em HTML 5 utiliza-se o método scale(1,-1) da classe canva.

4.3.2. Transladar os pontos da tela com o valor da altura dessa tela.

Em HTML 5 utiliza-se o método translate(0,h) da classe canva.

Código de exemplo sobre translação vertical:
<canvas id="idcanvas" width="400" height="450" style="border:1px solid #000000;"></canvas>
<script>
var canvas = document.getElementById("idcanvas");
var ctx = canvas.getContext("2d");

ctx.translate(0, 450);
ctx.scale(1, -1);
...
</script>

5. Códigos
Será apresentado alguns códigos que simulem o deslocamento de uma bola.

Código 1:
<!DOCTYPE html>
<html lang="pt_BR">
<head><title>Queda Livre</title>
<meta charset="utf-8">
<style>

</style>
</head>
<body>
<canvas id="canvas3" height="300" width="300"></canvas>
<script>
//get a reference to the canvas
var dx = 0;
var dy = 5;
var ctx;
var x = 150;
var y = 300;

function init() {
  return setInterval(draw, 40);
}

  var canvas3 = document.getElementById('canvas3');
  ctx = canvas3.getContext('2d');
// eixo-x para baixo
  ctx.translate(0,300);
// eixo-y positivo para cima
  ctx.scale(1, -1);

function draw() {
  ctx.clearRect(0,0,300,300);
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI*2, true);
  ctx.closePath();
  ctx.fill();

  //x -= dx;
  y -= dy;
}
init();
</script>
</body>
</html>
Link para o Código
 
Obs:
1) Primeiro executa translate(0,300) e depois ctx.scale(1, -1), senão gerará erro; ambas funções estão fora da função draw(), caso contrário, seriam executadas de acordo com a  função setInterval().
2) <canvas id="canvas3" height="300" width="300"></canvas> é o primeiro elemento do <body>

Código 2:
<script type="text/javascript">
var context;
var dx= 4;
var dy=4;
var y=150;
var x=20;

function draw(){
        myCanvas=document.getElementById("myCanvas");
    context= myCanvas.getContext('2d');
    context.clearRect(0,0,300,300);
    context.beginPath();
    context.fillStyle="#0000ff";
    context.arc(x,y,20,0,Math.PI*2,true);
    context.closePath();
    context.fill();
    if( x<20 || x>279)
            dx=-dx;
    if( y<20 || y>279)
        dy=-dy;
        x+=dx;
        y+=dy;

    }
setInterval(draw,20);
</script>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>HTML5 Bouncing Ball</title>
<style type="text/css">
canvas {
    border:1px solid #999;
}
</style>
</head>
<body>   
    <canvas id="myCanvas" width="300" height="300"></canvas>
</body>
</html>
Link para o Código

Obs:
1) O script foi colocado dentro do <head> e o código funciona normalmente.
O canvas tem width = 300 e hieght = 300, a área útil de desenho é width - 1 = 299 e height - 1= 299
O círculo tem raio igual a 20, o centro do círculo pode varia de 0 + 20 até 299 -20 = 279 para não ultrapassar a área do canvas.
2) if( x<20 || x>279)
            dx=-dx;
||: operador or lógico, retorna true se qualquer uma das expressões forem true.
dx: inicia com valor positivo, 4.
x: inicia com valor igual a 20.
x é menor que 20? Não, então x = x + dx até x + dx < 279
x + dx é maior que 279? Sim, então dx é multiplicado por -1 (muda de sinal), x = x - dx até x - dx < 20
x é menor que 20? Sim, então dx é multiplicado por -1 (muda de sinal), x = x + dx até x + dx < 279
...
3) if( y<20 || y>280)
        dy=-dy;
Mesmo raciocínio que x.
4) O círculo tem raio igual a 20, por isso o deslocamento de x e y estão entre 20 e 279.
5) Primeiro executa translate(0,300) e depois ctx.scale(1, -1), senão gerará erro; ambas funções estão fora da função draw(), caso contrário, seriam executadas de acordo com a  função setInterval().
6) <canvas id="canvas3" height="300" width="300"></canvas> é o primeiro elemento do <body>

Código 3:
Este código é uma modificação do anterior, foi transformado o sistema de coordenadas da tela para o sistema de coordenadas cartesiano.

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>HTML5 Bouncing Ball</title>
<style type="text/css">

canvas {
    border:1px solid #999;
}

</style>

</head>
<body>
<canvas id="myCanvas" width="300" height="300"></canvas>
<script type="text/javascript">
var context;
var dx= 4;
var dy=4;
var y=150;
var x=20;

function init() {

  return setInterval(draw, 20);
}
  var myCanvas=document.getElementById("myCanvas");
  context= myCanvas.getContext('2d');
  context.translate(0,300);
  context.scale(1, -1);

function draw(){
    context.clearRect(0,0,300,300);
    context.beginPath();
    context.fillStyle="#0000ff";
    context.arc(x,y,20,0,Math.PI*2,true);
    context.closePath();
    context.fill();
    if( x<20 || x>279)
            dx=-dx;
    if( y<20 || y>279)
        dy=-dy;
        x+=dx;
        y+=dy;

    }
init();
</script>
</body>
</html>
Link para o Código

Obs:
1) Este código não executa o script no <head>.
2) O sistema de coordenadas da tela foi transformado para o sistema de coordenadas cartesiano.
  Primeiro: context.translate(0,300);
  Segundo: context.scale(1, -1);
Se mudar a ordem da translação e depois a escala, este script não funciona, isso é uma caracteristica da linguagem de marcação,  em outros scripts a ordem pode ser inversa, é impotante testar o código.
A translação e a escala estão fora da função draw() porque senão iria repetir a transformação a cada execução do script pela função setInterval().

6. Conclusão
Após este estudo pode-se começar a trabalhar com velocidade e aceleração utilizando JavaScript e HTML 5.