Desenhando pontos e linhas com javascript puro (sem canvas)

Posted by micox at Janeiro 31st, 2008

Bem, infelizmente javascript não tem muitas capacidades de gerar gráficos, linhas, pontos, círculos, etc a não ser com CANVAS (infelizmente não bem suportado por todos os navegadores) ou por POG.

Fazer usando o canvas não teria graça hehe, então fui pro que eu gosto: a velha gambiarra.

Bom, gerar o ponto é fácil:

<style>
.ponto {  background-color: #0000FF; position: absolute; overflow: hidden;}
</style>
<script>
//global que guarda a largura da linha. Quanto maior, mais rápido o processamento.
window['larguraPonto']=2;
function geraPonto(x, y, nome, elempai) {
    //by Micox - www.elmicox.com - 31/01/08
    var pixel = document.createElement('div');
    pixel.id = nome;
    pixel.className = 'ponto';
    pixel.style.width = pixel.style.height = window['larguraPonto'] + 'px'
    pixel.style.left = x + 'px';
    pixel.style.top = y + 'px';
    return elempai.appendChild(pixel);
}
//chamando a função e gerando uma reta vertical
window.onload = function(){
 geraPonto(10,4,'ponto1',document.body)
 geraPonto(10,6,'ponto2',document.body)
 geraPonto(10,8,'ponto3',document.body)
 geraPonto(10,10,'ponto4',document.body)
 geraPonto(10,12,'ponto4',document.body)
 geraPonto(10,14,'ponto4',document.body)
 }
</script>

Perceba que eu coloquei algumas características do ponto via CSS e a definição da largura do ponto em uma variável global. Quanto MENOR for o valor da largura do ponto, logicamente irá demorar mais a plotagem do ponto.

Agora pra gerar uma linha inteira terei que usar meus exímios e velhos conhecimentos de matemática geométrica aprendidos no ensino médio hauehea (Vê se eu lembro disso. Lógico que colei do David Betz e dei umas adaptadas).

function geraLinha(x1, y1, x2, y2, nome, elempai) {
    //by Micox - www.elmicox.com - 31/01/08 - adaptado de http://www.davidbetz.net/graphics/
    var longPixel = document.createElement('div');
    if(elempai.constructor==String){ elempai = document.getElementById(elempai);}

    if(typeof(window['MicoxLinhas'])=='undefined'){
        window['MicoxLinhas'] = Array(); //este cidadão global irá guardar todas as linhas
    }
    window['MicoxLinhas'][nome] = Array()

    var steep = Math.abs(y2 - y1) > Math.abs(x2 - x1);
    if (steep) {
        var t = y1;
        y1 = x1; x1 = t;
        t = y2; y2 = x2;
        x2 = t;    }

    var deltaX = Math.abs(x2 - x1);
    var deltaY = Math.abs(y2 - y1);
    var error = 0;
    var deltaErr = deltaY;
    var xStep, yStep, modulo;
    var x = x1, y = y1;

    if (x1 < x2) {
        xStep = window['larguraPonto'];
        modulo = +1;
    }else {
        xStep = -window['larguraPonto'];
        modulo = -1;
    }

    if(y1 < y2) { yStep = window['larguraPonto']; }
    else { yStep = -window['larguraPonto']; }

    var nomeP = nome + x + '-' + y;

    if(steep) { window['MicoxLinhas'][nome][x] = geraPonto(y, x, nomeP, elempai);    }
    else { window['MicoxLinhas'][nome][x] = geraPonto(x, y, nomeP, elempai);    }

    var fim = modulo * x2;

    while( modulo * x < fim) {
        x = x + xStep;
        error = error + deltaErr;
        if(2 * error >= deltaX) {
            y = y + yStep;
            error = error - deltaX;
        }
        nomeP = nome + x + '-' + y;
        if(steep) { window['MicoxLinhas'][nome][x] = geraPonto(y, x, nomeP, elempai);    }
        else { window['MicoxLinhas'][nome][x] = geraPonto(x, y, nomeP, elempai);    }
    }
    return window['MicoxLinhas'][nome];
}

//brincando de desenhar
window.onload = function(){
 geraLinha(20,120,30,100,'minhaLinha1',document.body)
 geraLinha(30,100,60,100,'minhaLinha2',document.body)
 geraLinha(60,100,90,80,'minhaLinha3',document.body)
 geraLinha(90,80,130,80,'minhaLinha4',document.body)
 geraLinha(130,80,160,100,'minhaLinha5',document.body)
 geraLinha(160,100,210,105,'minhaLinha6',document.body)
 geraLinha(210,105,220,120,'minhaLinha7',document.body)
 geraLinha(220,120,20,120,'minhaLinha8',document.body)
 //agora só faltam as rodas haehaheuhaeu
}

Pronto, agora só falta fazer funções pra elipses e curvas hauheuhae. Não tô afim de brincar disso hoje não. Algum dia eu ou alguém faz uma função pra isso.

Percebam, senhores, que coloquei a opção de nomes nas linhas e pontos e coloquei elas dentro de um pai qualquer. Pra quê? Ué, pra poder apagar e mover as ditas cujas.

As funções de apagar:

function removePonto(nomeOuRef){
    //recebe o ID do ponto ou a referencia ao objeto HTML
    if(nomeOuRef.constructor==String){    nomeOuRef = document.getElementById(nome);    }
    nomeOuRef.parentNode.removeChild(nomeOuRef)
    try { delete nomeOuRef; } catch(e) { nomeOuRef = null }
}
function removeLinha(nomeOuRef){
    //recebe o ID da reta ou a referencia ao objeto array
    if(nomeOuRef.constructor==String){ nomeOuRef = window[nomeOuRef]; }
    for(var i in nomeOuRef){
        removePonto(nomeOuRef[i])
        try { delete nomeOuRef[i]; } catch(e) { nomeOuRef[i] = null }
    }
    try { delete nomeOuRef; } catch(e) { nomeOuRef = null }
}

As funções de mover nem precisava colocar aqui pois é aquele básico esquema de mover Divs:

function move(quem){
 //by Micox - www.elmicox.com - 30/01/08
 if(quem.constructor==String){ quem = document.getElementById(quem); }
 //movendo
 window['move'+quem.id] = setInterval( function(){
   quem.style.left = (quem.offsetLeft + 5) + 'px'
  }, 50);
}
function para(quem){
 //by Micox - www.elmicox.com - 30/01/08
 if(quem.constructor==String){ quem = document.getElementById(quem); }
 if(typeof(window['move'+quem.id])=='number'){
  clearInterval(window['move'+quem.id])
 }
}

Agora veja um exemplo completo e meu opalão se movimentando aqui.

- “Porra mico, que mané você heim? Não é mais fácil abrir um programa de imagens qualquer e desenhar diboas?”

- Sim meu caro cidadão, porém, digamos que você queira fazer um fluxograma em javascript (aqui você vê o fluxograma finalizado).
E aí? Nunca se sabe quando vamos precisar de algo, como diria George Boole.

Té a próxima, malucada.

Posted in funções, graficos, javascript| 5 Comments | 

ajaxPost - submeter formulários via Post facilmente

Posted by micox at Dezembro 28th, 2007

Ae cidadãos e cidadoas,

Sei que ninguém vai ler essa parada hoje, mas Feliz Natal (atrazado, agora já era) e próspero ano novo. Pois é…

Bom, lembram-se quando eu fiz a velha e boa função pra ajax simples ajaxGet? Pois é…
Lembram-se que o malandro aqui prometeu fazer uma versão pra submeter formulários via ‘Post’ também? Pois é…

Passados mil anos, o atoa aqui ainda não fez. Mas teve uma boa alma, amigo da criançada, membro do Webly que fez: o Cráudio, ops Klawdyo.
A parada ficou beleza. Ainda não testei 100% pois resolvi usar este ânimo pra fazer logo uma nova função pra ajax ultra-simples.

Então quem quiser submeter formulários via post através de ajax já sabe: usem a ajaxPost do José Cláudio e do Micox. :)

Em breve uma nova função fácil pra ajax englobando submissão simples, de formulários, função de callback (retorno), etc, etc.
I’ll be back!

Terminator - I'll be back

Posted in ajax, funções, javascript| 9 Comments | 

Animação para div aparecer gradativamente (alterando dimensões)

Posted by micox at Dezembro 13th, 2007

Hopa.

Que tal ao invés de usar simplesmente o velho "display: block" pra deixar determinada div visível, usar uma animaçãozinha pra dar um efeito especial melhor no seu site.

Veja aqui um exemplo.

Este tipo de coisa está disponível em todo framework javascript que se preze. Mas se você não tá afim de mexer com frameworks, é só adicionar a função abaixo na sua biblioteca:

function aparece(quem,speed){
    //Aparece o 'quem' gradativamente na velocidade especificada em speed (high, normal, slow)
    //by Micox - http://www.elmicox.com/2007/animacao-para-div-aparecer-gradativamente/

    if(typeof(quem)=='string'){
        quem = document.getElementById(quem);
    }
    if(typeof(window['micoxApareceGradativamente'+quem.id])!='undefined'){
        //esta animação já está em execucao, saio
        return true
    }
     var sty = quem.style;
     sty.visibility = 'hidden'
     var pos_init = sty.position;
     sty.position = 'absolute';
     if(sty.display=='none'){ sty.display = 'block' }
     var alt_init = parseInt(quem.offsetHeight);
     var lar_init = parseInt(quem.offsetWidth);
     var over_ini = sty.overflow;
     sty.overflow = 'hidden';
     sty.visibility = 'visible';
     sty.height = '0px';
     sty.width = '0px';

     if(typeof(quem.timeAparece)!='undefined'){
         clearInterval(quem.timeAparece);
     }
     quem.timeAparece=null;

     var loop = function(){
         var alt_atu = parseInt(sty.height);
         var lar_atu = parseInt(sty.width);
         if(alt_atu < alt_init){
             sty.height = (alt_atu + 5) + 'px';
         }
         if(lar_atu < lar_init){
             sty.width = (lar_atu + 25) + 'px';
         }
         if(alt_atu == 0 ){
             sty.position = pos_init;
         }
         if(alt_atu >= alt_init && lar_atu >= lar_init){
             //acabou
             clearInterval(quem.timeAparece);
             delete window[’micoxApareceGradativamente’+quem.id];
             sty.height = (alt_init) + ‘px’;
             sty.width = (lar_init) + ‘px’;
             sty.overflow = over_ini;
         }
     }
     switch(speed){
         case ‘high’: speed = 1; break;
         case ‘normal’: speed = 20; break;
         case ’slow’: speed = 40; break;
         default: speed = 10;
     }
     window[’micoxApareceGradativamente’+quem.id] = true;
     quem.timeAparece = setInterval(loop,speed);
}

Exemplo de uso (passando o ID):

<span onclick='aparece("apa","slow")'>clica</span>
<div id='apa' style='display: none; border: 1px solid black;'>asdfçlaksdfçl alsjdfçlajsdçlfjaçsldjfçlajsdçflj açlsdfjksd
asdfaslçkdfjçlaj<br />aç jdfljaçsldjkfçlaskjd f<br />lça jçdfljaçsdl fjkçalsjdf çlkajsçdlf</div>

Ou passando a referencia do elemento:

<span onclick='aparece(document.getElementById("apa"),"slow")'>clica</span>
<div id='apa' style='display: none; border: 1px solid black;'>asdfçlaksdfçl alsjdfçlajsdçlfjaçsldjfçlajsdçflj açlsdfjksd
asdfaslçkdfjçlaj<br />aç jdfljaçsldjkfçlaskjd f<br />lça jçdfljaçsdl fjkçalsjdf çlkajsçdlf</div>

Posted in funções, javascript| 19 Comments | 

Evento body onReady sem o uso de libs (DOM)

Posted by micox at Novembro 13th, 2007

Aberta novamente a temporada de postagens heheh.
Um serviço que eu estava fazendo maneirou e acho que posso voltar a ser mais periódico aqui no blog.

Bora lá com o on ready. Leia até o final :)

Bom, grande parte da malandragem que lê este blog usa frameworks e, portanto, devem conhecer as facilidades de uma função/evento on ready. Quem não conhece, vai achar esta postagem muito útil.

Perceba que não estou falando do onreadystate do AJAX nem do onready de iframes e afins, mas de onready no javascript. Continue lendo que entenderá.

Vou copiar aqui algumas descrições do que é o ‘on Ready’ pra não ter que ficar
definindo tudo novamente:

[…] Ready é semelhante ao onload do body, porém ele não
espera carregar imagens e objects, ou seja, assim que estiver carregado todo o HTML ela é executada! Muito útil! […] - jQuery Introdução - Felipe Diesel

[…]onReady é um método automaticamente chamado quando o DOM estiver completamente carregado, garantindo que todos os elementos referenciados na sua aplicação estarão disponíveis quando o script rodar. […] ( Introdução à bibliteca EXTjs - Fábio Vedovelli )

Nós usamos constantemente o ‘window.onload’ ou o ‘body.onload’ pra dizer que devemos iniciar a execução do nosso script. Porém, o evento onload espera tooooooda a tonelada de imagens/objetos/etc serem carregados antes de ser disparado.
Carambola, na imensa maioria das vezes nós precisamos apenas que os elementos HTML estejam carregados. É isso que o on ready faz! Que legal, dãã!

Em muitas bibliotecas este evento já está incluso (EXTjs e jQuery por exemplo), porém quem não usa bibliotecas ou cujas bibliotecas não tem o onready ficam a ver navios.
Tadáaaa: o Mico tem a solução!

“Chega de papo mico, você nunca foi de papo. Mostra logo um exemplo e o maldito script pra onload pra quem não usa bibliotecas.”

<script>
//vai funcionar rapidão pois não precisa esperar a imagem, só o carregamento do HTML
bodyOnReady(function(){
	alert('bodyOnReady ' + document.getElementById('teste').innerHTML)
})

//vai funcionar beleza, mas só depois que tooodos os elementos forem carregados
window.onload = function(){
	alert('onload ' + document.getElementById('teste').innerHTML)
}

//vai dar erro pois o elemento 'teste' ainda não foi criado
	alert('alert simples ' + document.getElementById('teste').innerHTML)

</script>
<body>
<img src='http://img119.imageshack.us/img119/4050/no20matinhoue1.jpg' alt='imagem (relativamente) grande' />
<div id='teste'>conteúdo da div</div>
</body>

Entenderam a parada aí? Pois é.

“Mas cadê a função bodyOnReady Mico? A parada aí não funcionou pois tá faltando a função bodyOnReady” - Calma, está abaixo. É só adicioná-la em seu script e usar conforme a sintaxe passada no exemplo acima.

function bodyOnReady(func){
 //call the function 'func' when DOM loaded
 //Version 2.0 - 03/03/2008 - based on Jquery bindReady
 //by Micox - www.elmicox.com - elmicox.blogspot.com - webly.com.br
 //http://www.elmicox.com/2007/evento-body-onready-sem-o-uso-de-libs/

 if(document.addEventListener && navigator.appName.indexOf('Opera')<0){ //FF
	document.addEventListener( "DOMContentLoaded", func, false );

 }else if(navigator.appName.indexOf('Internet Explorer')>=0){ //IE
	try { // by Diego Perini - http://javascript.nwbox.com/IEContentLoaded/
		document.documentElement.doScroll("left");
		func();
	} catch( error ) {
		setTimeout( arguments.callee, 20 );
		return
	}

 }else if(navigator.appName.indexOf('Opera')>=0){
	document.addEventListener( "DOMContentLoaded", function () {
		for (var i = 0; i < document.styleSheets.length; i++){
			if (document.styleSheets[i].disabled) {
				setTimeout( arguments.callee, 0 );
				return;
			}
		}
		func();
	}, false);
 }

}

Várias tentativas de fazer o onready também estão disponíveis na net se
quiserem testar. Esta aqui é só a minha versão (meio gambiarra pra variar).

Só testei no IE6, FF2 e OP9 e em poucas situações. Em caso de bug, não esqueçam de me avisar. Em caso de melhorias, manda ae.

Posted in DOM, funções, javascript| 8 Comments | 

Iframe com altura automática de acordo com o conteúdo

Posted by micox at Setembro 26th, 2007

Opa. Post rápido com código pequeno: Auto-dimensionamento de iframe

Script rápido que muita gente procura e fica brigando com códigos gigantescos.
Atenção: só funciona para iframes do mesmo domínio. De outro domínio dá erro de segurança.

Editado por conta de um bug no IE.


<script type='text/javascript'>
function iframeAutoHeight(quem,heu){
    //by Micox - elmicox.blogspot.com - elmicox.com - webly.com.br
    if(navigator.appName.indexOf("Internet Explorer")>-1){ //ie sucks
        var func_temp = function(){
            var val_temp = quem.contentWindow.document.body.scrollHeight + 5
            quem.style.height = val_temp + "px";
            alert(val_temp)        }
        setTimeout(function() { func_temp() },100) //ie sucks
    }else{
        var val = quem.contentWindow.document.body.parentNode.offsetHeight + 5
        quem.style.height= val + "px";
    }
}
</script>

uso no onload do iframe:


<iframe id='ha' src='teste.php' onload='iframeAutoHeight(this)' frameborder='0'></iframe>

Posted in javascript| 9 Comments | 

Next Postings »