Objota O mundo orientado a objetos

Animação com JavaScript e imagens Sprite

Posted on junho 14, 2011

Posted by Rodrigo Ireno

Olá a todos caros leitores do objota, antes de mais nada gostaria de dizer que tem sido difícil arrumar tempo para postar, devido a alguns projetos. Mas finalmente consegui arrumar um tempo para me dedicar a mais um artigo no objota.

Neste artigo vamos falar sobre animação utilizando imagens sprite e javascript. Recentemente o site de buscas google.com.br utilizou no lugar de seu logo uma animação muito legal para homenagear uma artista - que não me lembro qual. Mas enfim, fiquei realmente intrigado com aquela bela animação e fui atrás de saber como funcionava aquilo. A base da animação utiliza um conceito bem conhecido: imagens sprite, muito utilizadas em layouts de site para maximizar o carregamento das páginas web. Seguindo esta mesma linha de raciocínio criei o tutorial abaixo.

Primeiramente vamos definir o que é uma animação. Uma animação é uma sequencia de imagens mostradas a uma velocidade que dá a ilusão de existir algo animado, mesmo com desenhos e imagens estáticas.

Sabendo disso, para dar continuidade ao artigo precisamos de uma seqüência de imagens, e para que nós possamos utilizá-la ela precisa ser transformada em um sprite, ou seja, unir todas em uma única imagem. Abaixo segue a imagem que utilizei:

Como pode ver a imagem acima é um sprite de uma seqüência de imagens para animação. Sabendo disso fica claro que para animar esta imagem precisamos movimentar o seu background-position. E o javascript será a ferramenta que iremos utilizar para fazer esta animação.

Eu mesmo implementei um objeto que chamei de MovieClip, não querendo irritar os "flasheiros", hehe.

Dica: Caso ainda não saiba como implementar objetos em javascript veja este artigo.

movie-clip.js

window.MovieClip = function(posx){
 var that = this;
 this.count = 0;
 this.posx = posx || [];
 this.interval = 0;

 this.play = function(){
 that.interval = window.setInterval(function(){
 var s = document.getElementById('sprite');
 s.setAttribute('style','background-position: -'+that.posx[that.count]+'px 0px;');
 that.count++;
 if(that.count >= that.posx.length)that.count = 0;
 }, 300);
 };

 this.stop = function(){
 window.clearInterval(that.interval);
 that.count = 0;
 that.interval = 0;
 };

 this.isRun=function(){
 if(that.interval > 0)return true;
 return false;
 };
};

exemplo.html

<html>
<head>
<title>Sprite</title>
<script type="text/javascript" src="movie-clip.js"></script>
<style type="text/css">
#sprite{
 width: 59px;
 height: 37px;
 background-image: url(RushRun.gif);
 background-repeat: no-repeat;
 background-color: #fff;
}
</style>
</head>
<body>

<div id="sprite"></div>
<input type="button" value="play" id="control"/>

<script>
/*
Inicio o objeto passando um array de valores do eixo X da imagem
iniciando de zero
*/
var filme = new MovieClip([0,59, 117, 177, 235, 294]);
var bt = document.getElementById('control');

bt.onclick=function(){
 if(!filme.isRun()){
 filme.play();
 bt.setAttribute('value', 'stop');
 }
 else{
 filme.stop();
 bt.setAttribute('value', 'play');
 }
};
</script>
</body>
</html>

Veja que neste exemplo de implementação você deve fornecer um array contendo as coordenadas para a animação do sprite. Também deve configurar o número de frames por segundo.

Isso também nos leva a um outro assunto, a qualidade da animação, assim como dos vídeos, depende muito do número de frames por segundo que ele exibe. Quanto maior a quantidade de frames por segundo melhor será a qualidade do vídeo ou animação. Claro, sem apelar para qualidade da imagem e etc.

Bom, este foi meu artigo sobre animação com javascript utilizando sprite. Porém com CSS 3 e HTML 5 a capacidade de criação e os feitos com javascript serão ainda mais incríveis, realmente não vejo a hora destes novos formatos serem adotados e consolidados.

Comente! Qualquer dúvida ou sugestão a respeito deste artigo! Bons estudos.

arquivos para download: js-sprite

Simulando herança em JavaScript

Posted on fevereiro 14, 2011

Posted by Rodrigo Ireno

Já faz algum tempo que escrevi um artigo de como fazer classes em javascript, porém foi somente uma introdução. Na verdade javascript não é uma linguagem orientada a objetos, ela somente possui alguns recursos que possibilitam simular este conceito de programação.

Se fossemos comparar com todos os recursos que Java (por exemplo) disponibiliza, seria uma completa injustiça, pois atende em peso este conceito. Enquanto javascript sustenta-se apenas com functions, prototipagem e alguns métodos especiais.

Mesmo assim consegue simular uma série de conceitos da orientação a objetos, como:

  • Estruturas de objeto
  • Herança de atributos e métodos – (entre functions)

E pode acreditar, com isso já dá pra fazer muita coisa. Então mão na massa.

Existem várias formas de se fazer esta simulação, mas vou mostrar os métodos que prefiro usar, pois demonstra ter mais organização.

Herança via métodos call e apply

Call:

call( objeto, argumento1, argumento2, argumento3)

Apply:

apply( objeto, ArrayDeArgumentos )

Ambos os métodos trabalham de forma igual, o que eles fazem é trazer o contexto do objeto chamado para dentro do seu objeto atual, não entendeu?.  Vendo é mais fácil!

function Pai( nome, sobreNome){
 this.nome = nome;
 this.sobreNome = sobreNome;
}

function Filho(nome, sobrenome, idade){

 //call chama construtor do objeto Pai
 Pai.call(this, nome, sobrenome);

 this.idade = idade;

 this.mostra = function(){
 alert("Nome completo: "+this.nome+" "+this.sobreNome+"\nIdade: "+this.idade);
 };
}

var objota = new Filho("Maria", "Bonita", 35);

objota.mostra();

Veja que neste exemplo o que fiz foi chamar o construtor do objeto Pai, utilizando a função call. E veja que passei os parâmetros nome e sobrenome.

Agora vejamos este outro exemplo utilizando o método apply. Prefiro esse pois você escreve menos! Hehehe.


function Pai( nome, sobrenome){
 this.nome = nome;
 this.sobreNome = sobrenome;
}

function Filho(nome, sobrenome, idade){

 //apply chama construtor do objeto Pai
 Pai.apply(this, arguments);

 //também pode ser:
 //Pai.apply(this, new Array(nome, sobrenome));

 this.idade = idade;

 this.mostra = function(){
 alert("Nome completo: "+this.nome+" "+this.sobreNome+"\nIdade: "+this.idade);
 };
}

var objota = new Filho("Maria", "Bonita", 35);

objota.mostra();

Como vimos anteriormente o método apply recebe um array com os argumentos, certo. Então. A grande vantagem dele é que podemos utilizar a propriedade arguments herdada do objeto global (que todo objeto em javascript possui). Ele é um array justamente com todos os argumentos necessários para a construção do objeto pai. A única vantagem é a facilidade de implementação caso o objeto em questão tenha muitos argumentos. Você escreve bem menos.

Estes métodos pra mim já dão conta do recado, se você quiser se aprofundar um pouco mais aqui vai pelo menos os nomes dos outros métodos utilizados.

Herança via Object masquerading

Herança via Prototype

Multipla herança

É isso galera, até a próxima. E qualquer coisa comente aí.

Classes e Objetos em JavaScript

Posted on outubro 31, 2010

Posted by Rodrigo Ireno

O objetivo deste artigo é apenas mostrar a curiosa forma que toma uma classe feita em javascript puro.

Muitos usuários da biblioteca prototype não fazem questão de fazer desta forma afinal, nem sempre é viável. Para quem não sabe prototype é uma biblioteca que maximiza o poder de orientação a objetos do javascript. Porém no nosso caso presente, não a utilizaremos.

Veremos algumas coisas básicas comparando uma classe em php, por exemplo, e a classe em javascript.

A primeira coisa que podemos ver é que o JS não possui um envoltório chamado class para isso ele usa function.

Php:

class MinhaClasse{
 	//Aqui o conteúdo
}

JavaScript:

function MinhaClasse(){
 	//Aqui o conteúdo
}

Ótimo, e o construtor da classe. Em php se utiliza um método com o mesmo nome da classe ou __constructe. E em JS..  não tem!! Isso mesmo. O conteúdo do construtor fica mergulhado juntamente com os atributos.

Php:

class MinhaClasse{
        private $nome;
 	public function MinhaClasse($novoNome){
 		$this->nome = $novoNome;
 	}
}

JavaScript:

function MinhaClasse(novoNome){
  	var nome;
        this.nome = novoNome;
}

Vejamos agora uma declaração  dos famosos métodos get e set:

Php:

class MinhaClasse{
        private $nome;
 	public function MinhaClasse($novoNome){
 		$this->nome = $novoNome;
 	}
        public function getNome(){
 		return  $this->nome ;
 	}
        public function setNome($novoNome){
 		$this->nome = $novoNome;
 	}
}

JavaScript:

function MinhaClasse(novoNome){
  	var nome;
        this.nome = novoNome;
        this.getNome=function(){
 		return this.nome;
 	};
        this.setNome=function(otroNome){
 		this.nome = otroNome;
 	};
}

Agora vamos ver uma peculiaridade do javascript de passar uma função via parâmetro, ou dados no formato JSON. Veja como é simples:

Função via parâmetro:

function hello(){
 	document.write("Oi objota!");
}
function executaPraMim(funcaoQualquer){
 	funcaoQualquer(); //pronto! Ele chama a função
}

//passo uma função já implementada ou..
executaPraMim(hello());

//implementa-se no ato da parametrização
executaPraMIm(function(){
 	document.write("Essa eu implementei agora!");
});

Muito bacana não é!

Agora vejamos um exemplo bem simples de uma função que recebe dados no formato JSON.


function mostra(dados){
	Alert("O nome é: "+dados.nome+"\nemail: "+dados.email);
}
//vejamos a chamada
Mostra({nome: "Objota", email: "objota@teste.com.br"});

Neste artigo vimos como implementar classes, receber funções via parâmetro e dados no formato JSON. Neste artigo quis mostrar algumas peculiaridades do JS, nada em especial. Somente algumas dicas aos curiosos. Abaixo temos os exemplos completos coloque os dois arquivos no mesmo diretório e inicie a índex.html.

É isso! Até a próxima. Dúvidas, postem aí! 😉

Classes.js


//Classe Carro
function Carro(){
    var placa;
    var cor;

    this.getPlaca=function(){
        return this.placa;
    };

    this.setPlaca=function(novaPlaca){
        this.placa = novaPlaca;
    };
    this.getCor=function(){
        return this.cor;
    };

    this.setCor=function(novaCor){
        this.cor = novaCor;
    };
}

//Classe Pessoa
function Pessoa() {

    //@interface
    var nome;
    var idade;
    var email;
    var carro;
    //@end

    //@constructe
    this.carro = new Carro();
    this.carro.setPlaca(7520);
    this.carro.setCor("Amarelo");
    //@end

    //@implementation
    this.getCarro=function(){
        return this.carro;
    };

    this.getNome=function(){
      return this.nome;
    };

    this.getIdade=function() {
      return this.idade;
    };

    this.getEmail=function() {
      return this.email;
    };

    this.setNome=function(_nome) {
      this.nome = _nome;
    };

    this.setIdade=function(_idade) {
      this.idade = _idade;
    };

    this.setEmail=function(_email) {
      this.email = _email;
    };

    this.mostraValores=function() {
      return 'Nome: '+this.nome+
             '<br/>Idade: '+this.idade+
             ' anos<br/>Email: '+this.email+
             '<br/>Carro:<br/>* Placa:'+this.carro.getPlaca()+
             '<br/>**Cor: '+this.carro.getCor();
    };

    //Recebe uma função por parâmetro e executa
    this.executa=function(i,funcao){
          if(i > 0)
          funcao();
    };

    //Recebe dados no formato JSON via parâmetro
    this.mostraJson=function(dados){
          return 'Id:'+dados.id_conteudo+'<br/>Nome: '+dados.nome;
    };
    //@end
}

index.html


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Classes em javascript</title>
<script type="text/javascript" src="Classes.js"></script>
</head>

<body>
<script type="text/javascript">
  var Objota = new Pessoa();

  Objota.setNome('Objota - POO');
  Objota.setIdade(21);
  Objota.setEmail('email@objota.com.br');

  document.write(
    Objota.mostraValores()
  );
  document.write(
    Objota.getCarro().getPlaca()
  );

  //Altera placa do meu atributo carro, que é um objeto!
  Objota.getCarro().setPlaca(5051);

  //Passando função por parâmetro
  Objota.executa(1,function(){
      Objota.setNome('Rodrigo I.O.');
      Objota.setIdade(22);
      Objota.setEmail('bass_oliveira@hotmail.com');

      document.write(Objota.mostraValores());
  });

  //Passo dados no formato JSON via parâmetro {label: valor}
  document.write(Objota.mostraJson({id_conteudo: 50, nome: 'Manezinho'}));
</script>
</body>
</html>