Front End

15 set, 2014

Uma abordagem independente de plataforma para programação gráfica com HTML5 – Parte 02

Publicidade

Na primeira parte, vimos alguns destes tópicos: adoção de XML e SVG, mobilidade, caixa de pintura e efeitos. Nesta, serão abordados detalhes da biblioteca Raphaël, profundidade e WebGL, entre outros assuntos.

***

Raphaël, o artista

O exemplo na figura 5 mostra as capacidades básicas de desenho da biblioteca de desenho Raphaël e demonstra como utilizar o Inkscape como auxiliar na edição das imagens. As primeiras linhas de listagem 2 contêm o cabeçalho HTML e a conexão entre o Raphaël e o jQuery.

O programa de código aberto Inkscape, voltado para desenhos vetoriais, trabalha com SVG e exibe o código que ele gera em seu editor de XML integrado.
Figura 5: O programa de código aberto Inkscape, voltado para desenhos vetoriais, trabalha com SVG e exibe o código que ele gera em seu editor de XML integrado.

O último não é totalmente necessário para criar trabalhos com a biblioteca Raphaël, mas o jQuery torna muito mais fácil configurar um manipulador de eventos que irá suportar qualquer navegador (linha 54) e ao mesmo tempo garante que o código JavaScript não seja executado até que a interface DOM esteja pronta para isso (função $ na linha 8). A linha 15 inicializa a área de desenho de Raphaël. A linha 17 faz um pequeno círculo (figura 6). Os métodos de desenho sempre pertencem à área de desenho do objeto. As linhas 19 a 22 criam os múltiplos segmentos da curva de Bézier. Os caminhos a seguir para o desenho seguem os padrões do SVG, que não são exatamente famosos por sua legibilidade, mas é improvável que isso seja um problema. É possível criar strings numéricas e alfanuméricas com Inkscape. Se quiser desenhar uma forma de coração com a ferramenta curva de Bézier no Inkscape, selecione o caminho e pressione Editar | Editor de XML, e simplesmente copie o conteúdo do primeiro atributo, D, como o parâmetro path(). As linhas 24 e 25 configuram o atributo de preenchimento e traçado para #ff0, o código hexadecimal para o vermelho. As linhas 27 e 29 escrevem um texto dentro do coração e o pintam de amarelo. As coisas começam a ficar mais movimentadas com as funções de animação (linhas 36 a 51), que as próximas duas linhas irão chamar uma vez para inicializar a animação.

Listagem 2: Exemplo com a biblioteca Raphaël

01 <!DOCTYPE HTML>
02 <html>
03  <head>
04 script type="text/javascript" src="raphael‐min.js"> </script>
05 <script type="text/javascript" src="jquery‐1.6.2.min.js"></script>
06 <script type="text/javascript">
07  //jQuery run function after loading the document
08  $(function(){
09  //Colors the ball changes between
10  var colors = ["#000", "#800", "#f00", "#f80","#ff0"];
11 //Array counter
12 var counter = 0, zoom = 1;
13
14  //Drawing area 200x200 at position 50,50
15  var paper = Raphael(50, 50, 200, 200);
16  //Circle at position 40, 60, Radius 10
17  var circle = paper.circle(40, 60, 10);
18  //Path definition copied from Inkscape
19  var path = paper.path("m 41.416257,61.90761 c 17.95308,‐27.77874 " +
20 "56.06346,0.53741 56.06346,0.53741 0,0 38.055253,‐28.20692 " +
21 "55.982363,‐0.46836 34.96991,54.10886 ‐55.982363,112.02335 " +
22 "‐55.982363,112.02335 0,0 ‐91.0840396, ‐57.90515 ‐56.06346,‐112.0924 z");
23 //Red for fill and outline
24 path.attr("fill", "#f00");
25 path.attr("stroke", "#f00");
26 //Heart‐shaped text at center
27 var text = paper.text(100, 100, "Please\nclick me!");
28  //Text color yellow
29  text.attr("fill", "#ff0");
30
31  //Start animations
32  animateCircle();
33 colorChange();
34
35  //Re‐animate the ball every 2000 ms
36  function animateCircle(){
37  //Raphaël method for moving ball along path
38  circle.animateAlong(path, 2000, false);
39  //Reset timer
40  setTimeout(animateCircle, 2000);
41 }
42
43  //Change ball color at random intervals
44  function colorChange(){
45  //Raphaël function changes element attributes
46  circle.attr("fill", colors[counter]);
47  //Increment elements of array colors, back to 0 if needed
48  counter = (counter < 5) ? ++counter : 0;
49  //Reset timer
50 setTimeout(colorChange, Math.random()*50);
51 }
52
53 //jQuery click handler for heart
54  $(path.node).click(function(){
55  //> 1 ‐> zoom out and vice‐versa
56  zoom = (zoom > 0.95) ?
57  zoom ‐ 0.1:
58  zoom + 0.1;
59  //animate heart scaling with "bounce" type
60  path.animate({scale:zoom}, 500, "bounce")
61 });
62  });
63  </script>
64  </head>
65  <body></body>
66 </html>
A biblioteca Raphaël ainda suporta navegadores antigos, como o Internet Explorer 6. Sem intervenção do desenvolvedor, o Raphaël converte comandos de desenho e animações para VML, formato específico da Microsoft.
Figura 6: A biblioteca Raphaël ainda suporta navegadores antigos, como o Internet
Explorer 6. Sem intervenção do desenvolvedor, o Raphaël converte comandos de desenho e animações para VML, formato específico da Microsoft.

 

 

Sempre em movimento

A instrução animateCircle() na linhas 36 a 41 causa um um pequeno movimento de bola em volta da forma de coração. O método animateAlong() da biblioteca Raphaël é usado para isso. O script passa nos parâmetros (path, 2000, false), que representa o caminho existente, a duração da animação, e false para desativar a rotação do objeto, que não teria efeito visível sobre a bola. A linha 40 define um tempo limite para que a função JavaScript chame novamente a animação após seu término em um movimento de loop.

A função colorChange() conta os cinco elementos de cores e atribui a cor de preenchimento para o círculo. O parâmetro setTimeout() na linha 50, em seguida, torna-se a função para executar novamente em intervalos aleatórios. Isso passa o manipulador de cliques para o coração. Ele usa o manipulador de eventos jQuery como camada de abstração para fornecer suporte para o Internet Explorer 6 também. Mesmo nesse navegador antigo, a biblioteca Raphaël mostra o potencial de suas habilidades de desenho (figura 6). Quando o coração é clicado, é atribuído um fator de escala que oscila entre um fator 0,1 e 1 do valor original.

O código mostra que o Raphaël pode mudar muitos atributos SVG de uma só vez e suporta transições suaves. Para fazer isso, o método animate() é utilizado; ele espera um objeto que compreende atributo/pares de valores, a duração da animação, e o tipo de animação como parâmetros. bounce, quando aplicado à escala do objeto, causa um efeito no estilo de geleia balançando.

Profundidade

Há alguns anos, o VRML foi uma tentativa de incorporar recursos 3D interativos em páginas HTML. No entanto, isso não foi muito bem sucedido devido ao fato de que não havia navegadores com suporte para linguagens de modelagem 3D de forma nativa. As coisas parecem muito melhores agora para o WebGL, uma API de gráficos 3D baseado em OpenGL ES 2.0 que dá ao navegador acesso ao acelerador de hardware da placa gráfica. A atual safra de navegadores, com exceção do Internet Explorer, já suporta isso. A Microsoft afirma estar preocupada com a segurança do hardware quando seu acesso é exposto através da Internet, de modo que nenhum suporte pode ser esperado a partir de Redmond no futuro (figura 7).

Um precursor do futuro da Microsoft na web? A página de jogos HTML5 Tubagames [21], diz não ao Internet Explorer por causa de sua falta de suporte ao WebGL.
Figura 7: Um precursor do futuro da Microsoft na web? A página de jogos HTML5 Tubagames, diz não ao Internet Explorer por causa de sua falta de suporte ao WebGL.
O WebGL é apenas uma parte do Canvas HTML. Caso queira usá-lo, é preciso chamar o método canvas.getContext (); com o parâmetro webgl. Agora, os desenvolvedores provavelmente devem testar o uso em cada um dos navegadores, pois cada um espera parâmetros específicos como experimental-WebGL, moz-WebGL e na webkit-3d. É necessário testar essas variantes até que o método getContext() retorne um objeto válido.

WebGL: uma tecnologia 3D dos anos 80

O WebGL suporta acesso direto aos recursos do OpenGL em JavaScript. Desenvolvedores mais experientes com modelagem 3D serão capazes de fazer praticamente qualquer coisa que possa ser programada em OpenGL no navegador sem um plugin – com exceção de operações computacionalmente mais caras do tipo que os motores de jogos atuais utilizam ou então o suporte diferenciado para recursos Blender. O interpretador JavaScript simplesmente não foi projetado para computação de alto desempenho contendo vetores e matrizes, apesar de alguns progressos existirem nesse sentido nos últimos anos.

Alguns desenvolvedores web têm dificuldade para começar na programação WebGL por conta de sua abordagem de baixo nível. O princípio de design do WebGL passa muito longe das APIs orientadas a objetos de hoje – e isso não é nenhuma surpresa, já que as raízes do OpenGL remontam à década de 1980. Dito isso, existem várias bibliotecas para ajudar programadores com nenhum conhecimento em C ou GL. O GLGE e o SceneJS são muito maduros nesse sentido. Os exemplos simples presentes nas listagens 3 e 4 desenham o cubo mostrado na figura 8, com a ajuda de GLGE. O cubo é composto por duas partes: um arquivo HTML com código JavaScript e um arquivo XML que define os elementos para a o objeto 3D. O arquivo HTML (listagem 3) contém um elemento de tela e integra a biblioteca GLGE, que executa o método load(), que por sua vez carrega o arquivo XML da cena depois de inicializar o objeto (linhas 5 a 12). A função chamada nas linhas 14 a 20 fazem o trabalho pesado depois de carregada a cena. Essa função começa por inicializar a tela como o processador e a cena 3D. A variável doc contém a definição da cena como um documento XML DOM analisável (listagem 4). Ele inclui uma definição de cena com um ID de cena principal, que as linhas 16 e 17 fornecem para o renderizador. Tudo o que precisa ser feito agora é uma chamada para render(), e o navegador vai exibir um cubo com iluminação natural.

Listagem 3: Código HTML WebGL

01 <!DOCTYPE HTML>
02 <html>
03  <head></head>
04  <body>
05  <canvas id="canvas" width="300" height="300"></canvas>
06  <script type="text/javascript" src="glge‐compiled‐min.js"></script>
07
08 <script type="text/javascript">
09  var canvasElement =
10  var doc = new GLGE.Document(); document.getElementById("canvas");
11
12 doc.load("defs.xml");
13
14 doc.onLoad = function() {
15 var renderer = new GLGE.Renderer(canvasElement);
16 var scene = new GLGE.Scene();
17 scene = doc.getElement("mainScene");
18 renderer.setScene(scene);
19 renderer.render();
20 } 
21 </script>
22  </body>
23 </html>
O navegador como um renderizador: o WebGL combina OpenGL ES 2.0 e JavaScript.
Figura 8: O navegador como um renderizador: o WebGL combina OpenGL ES 2.0 e JavaScript.

A definição de cena combina as coordenadas espaciais de seis triângulos para criar uma malha 3D (linhas 5 a 10). O triângulo é a forma básica da qual todos os programas 3D dependem, inclusive o GLGE. As coordenadas foram selecionadas para criar um cubo com um comprimento da aresta com valor 1. Um objeto necessita de um material de preenchimento para definir as propriedades de sua superfície. Esse exemplo apenas define os reflexos e a cor (linha 16). O elemento de cena posiciona o preenchimento, a visualização e a luz, sem a qual você não veria nada.

Movimento e luminosidade

Esse exemplo simples mostra que não há necessidade de se preocupar efetivamente com a programação caso sua opção seja usar o GLGE. O que você não vê, nesse exemplo, é do que tratam os impressionantes recursos da biblioteca: o GLGE suporta animação baseada em quadro-chave, o que também fornece um sistema de esqueleto primitivo para personagens animados.

Holofotes, pontos de luz e destaques direcionados fornecem uma iluminação realista, assim como o mapeamento normal (isto é, interpolação da iluminação entre os painéis de preenchimento). A figura 9 mostra o ambiente de mapeamento em ação. Como no exemplo, é possível abordar todos esses recursos através de uma API orientada a objetos com XML declarativo; programação OpenGL não é necessária. Para eliminar a necessidade de os desenvolvedores digitarem matrizes longas manualmente para definição de preenchimento (listagem 4, nas linhas 5 a 10), o editor Blender 3D tem dois plugins de exportação, e nenhum deles trabalha com a versão atual do Blender, a versão 2.5, em nosso laboratório.

Listagem 4: Definição de cena da figura 8

01 <?xml version="1.0"?>
02 <glge>
03 <mesh id="cube">
04 <positions>
05 1,1,1, 1,1, ‐1,  1,1,1 ,  ‐1,1,-1,  -1,1,1, 
06  ‐1, ‐1, ‐1, ‐1, ‐1, 1, ‐1, 1, 1, ‐1, ‐1,
07  1, ‐1, ‐1, 1, ‐1, 1, ‐1, ‐1, ‐1, 1, ‐1,
08  1, 1, 1,1,1, ‐1,1, ‐1, ‐1,1,1,1, 1,1, ‐1, 1,‐1, ‐1, ‐1, 1, 1,
09 1,1,1,1,1, ‐1,1, ‐1, ‐1,1,1,1, 1,1, ‐1, 1,‐1, ‐1, ‐1, 1, 1,
10 1,1,1,1,1, ‐1,1, ‐1, ‐1,1,1,1, 1,1, ‐1, 1,‐1, ‐1, ‐1, 1, 1,
11 </positions>
12  </mesh>
13
14  <material id="cubeMat" specular="1" color="#8822bb" />
15  <camera id="mainCamera" />
16  <scene id="mainScene" camera="#mainCamera" ambient_color="#fff">
17 <object id="cube" mesh="#cube" loc_x="0.5" loc_y="‐0.1" loc_z="‐10"
18 rot_x="0.8" rot_y="0.9" rot_z="‐0.1"
19 type="L_POINT" />
20 material="#cubeMat" />
<light id="mainlight" loc_x="20" loc_y="16g" loc_z="1" rot_x="‐1.5" color="#ff8"
</scene>
21
22 </glge>
Figura 9: As superfícies brilhantes refletem o ambiente em uma cena criada com GLGE.
Figura 9: As superfícies brilhantes refletem o ambiente em uma cena criada com GLGE.

Mais luz do que sombras

Se considerarmos os recentes novos desenvolvimentos na estrutura do HTML, veremos mais luzes do que sombras: o Canvas e o SVG, que agora é – finalmente – suportado pelo Internet Explorer, tornaram a linguagem de marcação para Internet uma impressionante ferramenta de desenho para interfaces web. A conformidade com os padrões dos navegadores atuais é muito melhor agora para recursos Canvas e SVG do que foi durante a guerra dos navegadores, com a atual safra de navegadores respondendo mais ou menos de acordo com as especificações atuais.