Webly: Desenhando com Canvas - Webly

Ir para

Regras para postagem

É permitido postar livremente respostas com comentários, testes e avaliações dos scripts. Postagens contendo dúvidas sobre o script, deverão ser postadas no fórum principal de javascript/ECMAScript/AJAX.

IMPORTANTE: Todos os tutoriais postados neste fórum irão automaticamente para o portal Webly. Contribua você também e faça parte da equipe de colaboradores que fazem a evolução da web. Obrigado.
Página 1 de 1

Desenhando com Canvas Avaliar tópico: ***** 1 Votos

#1 Membro offline   JulioGreff Ícone

  • Ícone
Grupo:
Membros
Posts:
206
Cadastrado:
20-outubro 06
Localização:
Farroupilha - RS
Interesses:
JavaScript, Ajax, WebStandards, Ruby, PHP...

Postou 30 junho 2007 - 11:25

Nome: Desenhando com Canvas
Autor: JulioGreff da equipe Webly
Licença Creative Commons: Este conteúdo só pode ser copiado caso seja LINKADO para este original e citado o nome do autor antes de qualquer outro texto.

Canvas (<canvas>) é um elemento HTML que pode ser usado para desenhar através de JavaScript, ou outra linguagem de scripting provida pelo browser. Podemos usa-lo para fazer desenhos, composições com imagens e até animações. Já foram criados até alguns jogos básicos através de canvas.
Esse elemento funciona apenas em browsers mais modernos. Firefox 1.5+, Opera 9, Safari ou qualquer outro browser com a engine Gec outro browser com a engine Gecko 1.8. E não, não funciona no IE, eu havia dito browsers e modernos.

Marcação
Diferente do SVG, todo nosso desenho será feito via scripting, e não temos tanto controle sobre os elementos desenhados. O que devemos fazer é adicionar nossa "área de desenho" na marcação:

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

A altura e largura do canvas são definidos, respectivamente, por height e width, que também podem ser definidos pelo DOM ou CSS. Caso não sejam especificados, assumem 300px de largura e 150px de altura por padrão.

Acessando o Canvas
Agora vamos ao script. Primeiramente, precisamos esperar o documento carregar para podermos começar a desenhar, caso contrário seremos avisados que o elemento não existe. Depois, precisamos obter o elemento do canvas, através de document.getElementById, nada de espetacular.
Para termos acesso às funções de desenho, precisamos acessar tal contexto. Cada elemento canvas possui o método getContext, que leva apenas um parâmetro, que logicamente é o tipo do contexto de desenho. Atualmente, somente o contexto "2d" é aceito, mas no futuro poderá ser implementado "3d" também. Agora vamos juntar tudo, e criar o código:

window.onload = function() {
   var canvas = document.getElementById("canvas");
   canvas = canvas.getContext("2d");
 }

Agora já acessamos o contexto de desenho e podemos começar a desenhar, embora ainda não vejamos nada em nosso canvas canvas. Ele ainda é apenas uma área transparente.
Para desenharmos, usaremos aquele clássico sistema de coordenadas (x,y), como nos programas de design e nas aulas de matemática. Cada unidade corresponde a 1 pixel, e o topo esquerdo é a posição (0,0). Todas as coordenandas são definidas com base nesse ponto.
Formas
Em canvas, existe apenas uma forma primitiva, que são os retângulos. Todas as outras formas são criadas através da combinação de "paths", que vamos ver logo depois. Para o desenho de retângulos, podemos utilizar 3 funções:
  • fillRect(x, y, largura, altura): desenha um retângulo preenchido
  • strokeRect(x, y, largura, altura): desenha um retângulo sem preenchimento, apenas contorno
  • clearRect(x, y, largura, altura): limpa uma área retangular do desenho
Observe o exemplo abaixo, utilizando os três métodos. Primeiro, preenchemos um retângulo. Logo após, limpamos uma área de dentro do retângulo anterior, e dentro dessa área limpa contornamos outro retângulo. Vejamos um boneco bem, digamos, "quadradão":

window.onload = function() {
   var canvas = document.getElementById("canvas").getContext("2d");
   canvas.fillRect(0,0,150,150);
   canvas.clearRect(15,25,30,30);
   canvas.strokeRect(17,27,26,26);
   canvas.clearRect(105,25,30,30);
   canvas.strokeRect(107,27,26,26);
   canvas.clearRect(63,65,24,30);
   canvas.clearRect(15,120,120,10);
 }


Imagem


Cores
Cores também são um aspecto "chatinho" de se trabalhar em Canvas. Não é possível definir uma cor especificamente para uma forma, é algo mais genérico. Usamos as propriedades fillStyle e strokeStyle, que definem a cor para preenchimento e contorno, respectivamente, para as formas desenhadas posteriormente (não temos controle sobre formas desenhadas anteriormente). Elas aceitam valores rgb, rgba, valores hexadecimais e nomes em inglês ("red", "green", "blue"...). Vamos fazer uma modificação no desenho anterior:

window.onload = function() {
   var canvas = document.getElementById("canvas").getContext("2d");
   canvas.fillStyle = "#ffff66"
   canvas.strokeStyle = "blue";
   canvas.fillRect(0,0,150,150);
   canvas.clearRect(15,25,30,30);
   canvas.strokeRect(17,27,26,26);
   canvas.clearRect(105,25,30,30);
   canvas.strokeRect(107,27,26,26);
   canvas.strokeStyle = "rgba(0,0,0,0.8)";
   canvas.strokeRect(63,65,24,30);
   canvas.fillStyle = "#ff0000";
   canvas.fillRect(15,120,120,10);
 }


Imagem


Paths
Os paths (caminhos), são basicamente linhas que assumem vários formatos que, quando combinadas, nos permitem criar as mais diversas formas. Se você tem uma base, mesmo que mínima, sobre desenho vetorial, vai entender perfeitamente o que digo.
Para desenharmos esses "caminhos", precisamos iniciar um novo path, através do método beginPath. Apesar de termos iniciado um caminho, ainda não há nada no canvas.
Depois de iniciado, precisamos invocar os métodos que especificam como o path será desenhado, que forma ele deverá ter. Podemos desenhar linhas, arcos, curvas e retângulos. Não vou explicar os métodos agora pra não perder a graça.
Após termos desenhado todo o path através dos métodos que (não) citei acima, pode-se fecha-lo (opcional se o path será preenchido) através do método closePath. Ele tentará traçar uma linha reta do último ponto para o ponto inicial, se o caminho já não estiver fechado ou tiver apenas um ponto.
Embora a forma esteja "desenhada", ela ainda não aparece no canvas. Isso porque todo o caminho fica na memória até que o passemos para o canvas. Para tal, precisamos preenchê-lo ou contorná-lo, através dos métodos fill e stroke, respectivamente.
Nossos primeiros paths serão baseados em linhas, que podem ser desenhadas pelo método lineTo(x, y). Ele desenha uma linha do ponto corrente do path até as coordenandas (x, y) passadas como parâmetro. Vamos ver um exemplo:

canvas.beginPath();
 canvas.lineTo(150, 150);
 canvas.lineTo(0, 150);
 canvas.lineTo(0, 0);
 canvas.fill();
 canvas.beginPath();
 canvas.moveTo(0,0);
 canvas.lineTo(150, 0);
 canvas.lineTo(150, 150);
 canvas.closePath();
 canvas.stroke();


Imagem


Desenhamos dois triângulos, um preenchido e outro contornado. Note que, quando usamos fill, não é necessário fechar a forma. Note também uma chamada ao método moveTo, será um dos métodos mais utilizados em suas composições. Fica o mistério...
O método moveTo move a origem do path para qualquer ponto do canvas. É equivalente a levantar o pincel e começar a desenhar a partir de outro ponto. Toda vez que adicionamos um path à lista, essa origem será o lugar do último ponto desenhado, a menos que ele fosse mudado. Veja o exemplo anterior sem a chamada ao moveTo.
Iniciamos então com os arcos. Eles são a base para a criação de qualquer tipo de forma circular, círculos, semicírculos, semi-semicírculos... São criados através do método arc(x, y, radius, startAngle, endAngle, anticlockwise)que na minha opinião é um método um pouco mais complicado.
Os parâmetros x e y determinam o centro do arco. radius indica o tamanho do raio, em pixels. startAngle e endAngle são os ângulos de início e fim do arco, medidos em radianos. Sou péssimo nisso aí, e uso o seguinte código de conversão (retirado do MDC):

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

Pra quem também não é muito bom em geometria, 0 e Math.PI desenham um meio círculo e 0 e Math.PI*2 desenham um círculo completo.
Há também o último parâmetro, anticlockwise, booleano, que define se o círculo deverá ser desenhado para o sentido horário (false) ou anti-horário (true).

// Exemplo do MDC
 canvas.beginPath();
 canvas.arc(75,75,50,0,Math.PI*2,true); // Rosto
 canvas.moveTo(110,75);
 canvas.arc(75,75,35,0,Math.PI,false);   // Boca (sentido horário)
 canvas.moveTo(65,65);
 canvas.arc(60,65,5,0,Math.PI*2,true);  // Olho Esquerdo
 canvas.moveTo(95,65);
 canvas.arc(90,65,5,0,Math.PI*2,true);  // Olho Direito
 canvas.stroke();


Imagem


Também é bom lembrar que o último ponto do círculo será o final da curva, e não o centro dele.
Terminando as formas, temos as curvas quadráticas e curvas de Bézier. Elas têm um uso mais complexo (bem mais complexo), principalmente pra quem não tem experiência com design. Como também não sou um mestre do design, fico devendo um exemplo (não gosto de copiar exemplos que eu não tenha conseguido reproduzir). Temos muita coisa interessante no MDC.
  • quadraticCurveTo(cp1x, cp1y, x, y)
  • bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
Os parâmetros x e y definem as coordenandas para o ponto de fim das curvas. cp(n)x e cp(n)y indicam as coordenadas dos pontos de controle das curvas. Esses pontos são onde controlamos a curvatura. É lógico que sem um tipo de visualização é muito mais difícil tentar algo na tentativa-e-erro. Boa sorte!
Transparência
Existem duas maneiras de implementar a transparência em nossos desenhos: através de uma definição de cor rgba ou pela propriedade globalAlpha. O valor varia de 0 (forma transparente) a 1 (forma opaca).
Um exemplo, utilizando as duas técnicas. Claro, não há efeito...

canvas.fillStyle = "rgba(255,0,0,0.5)"; // Transparência 50%
 canvas.globalAlpha = 0.5;

Agora sim, um exemplo mais prático:
canvas.fillStyle = "rgba(255, 0, 0, 1)";
 canvas.fillRect(0, 0, 100, 100);
 canvas.fillStyle = "rgb(0, 255, 0)";
 canvas.globalAlpha = 0.5;
 canvas.fillRect(50, 50, 100, 100);


Imagem


Gradientes
Geralmente costuma-se citar primeiro os estilos de linha para depois os gradientes. Acho que essa parte será mais interessante, e explicarei antes dos estilos de linha. Em canvas só podemos criar dois tipos de gradiente: linear e radial, e fazemos isso através dos métodos createLinearGradient e createRadialGradient. Eles podem ser atribuídos a variáveis, já que poderão ser usados várias vezes, sem a necessidade de recria-los. Eles podem ser utilizados para definir fillStyle e strokeStyle.
O método createLinearGradient leva 4 parâmetros: x1, y1, x2 e y2. Os dois primeiros definem as coordenadas do ponto inicial e os dois últimos do ponto final. Já createRadialGradient leva 6: os três primeiros definem o círculo central (x1, y1 e raio1, nessa ordem) e o círculo de fora (x2, y2 e raio2, nessa ordem). Vamos à um exemplo:

var lineargradient = canvas.createLinearGradient(0,0,150,150);
 var radialgradient = canvas.createRadialGradient(75,75,0,75,75,100);

Mesmo criados e atribuídos ao preenchimento ou contorno, os gradientes vistos acima não têm efeito algum, pois não definimos as cores do gradiente. Precisamos definir "color stops", que são pontos que definem a cor do gradiente. Fazemos isso através do método (método do objeto gradiente, e não do canvas) addColorStop, que leva os parâmetros posição e cor. A posição pode ser um valor entre 0 e 1, que é relativo ao gradiente, e a cor pode ser definida como no CSS3 (rgb, rbga, #rrggbb, "red", "green", "blue"...).

var radial = canvas.createRadialGradient(75,75,0,75,75,60);
 radial.addColorStop(0,'red');
 radial.addColorStop(0.5,'orange');
 radial.addColorStop(0.9,'yellow');
 radial.addColorStop(1,"rgba(255,255,255,0)");
 canvas.fillStyle = radial;
 canvas.beginPath();
 canvas.arc(75, 75, 60, 0, Math.PI*2, true);
 canvas.fill();


Imagem


Estilos de Linha
Podemos modificar alguns estilos das linhas (contornos) em nosso desenho. O primeiro estilo que veremos é a espessura da linha, definida pela propriedade lineWidth, que é definida em pixels. Um exemplo utilizando linhas randonâmicas:

for(var i = 0; i < 10; i++) {
   canvas.lineWidth = Math.round(Math.random()*10);
   canvas.beginPath();
   canvas.moveTo(i * 14, 5);
   canvas.lineTo(i * 14, 140);
   canvas.stroke();
 }


Imagem


A propriedade lineCap define como deverão ser as extremidades das linhas. Os valores possíveis são "butt", "round" e "square". Com o valor "butt", as linhas terminarão exatamente nas coordenadas que foram definidas. Com o valor "round", será adicionada um semicírculo ao final da linha. Já "square" adiciona um retângulo com tamanho igual a metade da espessura da linha.
Temos também a propriedade lineJoin, que define como as linhas que se encontram devem ser. Pode receber os valores "mitter", "round" e "bevel". "mitter" faz as extremidades alongarem-se até se encontrarem em um único ponto, e esse alongamento é definido pela propriedade "mitterLimit". "round" arredonda e "bevel" faz um corte um pouquinho arredondado.

Finalizando...
Tive como objetivo apenas fazer uma introdução ao uso de canvas e suas capacidades vetoriais. Canvas também pode criar composições com imagens, texturas, fazer animações, e até jogos. É uma ótima ferramenta, apesar de um tanto limitada quanto a compatibilidade com outros softwares (IE, no caso).
Espero que tenha sido de utilidade.
0

#2 Membro offline   Daniel Vidal Ícone

  • webly@workaholic.to.nessa
  • Ícone
Grupo:
Administradores
Posts:
1115
Cadastrado:
27-outubro 06
Localização:
São Caetano do Sul - SP

Postou 09 julho 2007 - 07:06

Parabéns Julio!!!
Ficou muito bom esse seu Tuto!!
:thumbsup:
===== Não sei de nada, mas sou cheio de ideias =====
0

#3 Membro offline   JulioGreff Ícone

  • Ícone
Grupo:
Membros
Posts:
206
Cadastrado:
20-outubro 06
Localização:
Farroupilha - RS
Interesses:
JavaScript, Ajax, WebStandards, Ruby, PHP...

Postou 11 julho 2007 - 09:56

Valeu! Pena que não consegui aprontar as imagens...
Júlio Greff de Oliveira
JavaScript Turbinado
Blog: http://www.juliogreff.blog.br
0

#4 Membro offline   Bermonruf Ícone

  • Bernardo Rufino
  • Ícone
Grupo:
Moderadores
Posts:
762
Cadastrado:
04-outubro 06
Localização:
Rio de Janeiro, RJ
Interesses:
Ruby On Rails, PHP, Javascript, Ajax, CSS, XHTML, DOM, XML

Postou 11 julho 2007 - 11:24

Quer que eu faça as imagens, Júlio?
Blog: http://bermonruf.wordpress.com
0

#5 Membro offline   JulioGreff Ícone

  • Ícone
Grupo:
Membros
Posts:
206
Cadastrado:
20-outubro 06
Localização:
Farroupilha - RS
Interesses:
JavaScript, Ajax, WebStandards, Ruby, PHP...

Postou 12 julho 2007 - 04:00

Se puder, agradeço muito... Pode passar por e-mail, se der. Valeu!
Júlio Greff de Oliveira
JavaScript Turbinado
Blog: http://www.juliogreff.blog.br
0

#6 Membro offline   Thiago Ananias Ícone

  • Ícone
Grupo:
Moderadores
Posts:
1033
Cadastrado:
14-julho 06
Localização:
São Paulo - SP

Postou 23 julho 2007 - 12:14

Caramba...já vi algo bem parecido em Java hein?! :P
Nhenhenhê, tititi, blábláblá!!
0

Página 1 de 1


Resposta rápida

  • Diminuir tamanho
  • Aumentar tamanho
  

1 usuário(s) está(ão) lendo este tópico
0 membro(s), 1 visitante(s) e 0 membros anônimo(s)