tadarank afiliados

31 janeiro, 2008

Desenhando pontos e linhas com javascript puro (sem canvas)

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.

Gostou da dica acima? Então clica nos botões de compartilhamento abaixo e me ajude a dica a subir no Google.

4 comentários:

  1. Cara, parabéns! Muito legal este algoritmo. Peguei esta ideia para colocar num site (ainda em construção) de cursos online. Isto vai me ajudar muito na hora em que for pedido para o aluno construir, por exemplo, um botão. Abraços, Eduardo Scopel.

    ResponderExcluir
  2. Essa gera um círculo:

    function geraCirculo(x,y,r,nome,elempai,precisao){
    //by Will - 0w0w7w@gmail.com - 23/03/13
    var longPixel = document.createElement('div');
    if(precisao == undefined){
    precisao = 5;
    }
    if(elempai.constructor==String){ elempai = document.getElementById(elempai);}

    if(typeof(window['WillCirc'])=='undefined'){
    window['WillCirc'] = Array(); //este cidadão global irá guardar todos os circulos
    }
    window['WillCirc'][nome] = Array()

    var nomeC = nome + x + '-' + y;
    var ang = 0;
    var x2;
    var y2;
    //usa seno e cosseno para gerar o círculo, sem segredo, so tem que converter para radianos
    var tmp_x=x+Math.cos(Math.PI/(180/ang))*r;
    var tmp_y=y+Math.sin(Math.PI/(180/ang))*r;
    while(ang < 360){
    ang=ang+precisao; //define a precisao
    x2 = x+Math.cos(Math.PI/(180/ang))*r;
    y2 = y+Math.sin(Math.PI/(180/ang))*r;
    //faz circulos que ficam com falhas quando grandes
    //window['WillCirc'][nome][ang] = geraPonto(x2,y2,nomeC,elempai);
    geraLinha(tmp_x,tmp_y,x2,y2,nomeC,elempai);

    //faz coisas interessantes...excetos circulos
    //geraLinha(tmp_x,tmp_y,x2,y2,nomeC,elempai);

    tmp_x=x2;
    tmp_y=y2;

    }
    //document.write('teste: '+Math.sin(Math.PI/(180/30)));
    return window['WillCirc'][nome];
    }

    a chamada é assim:
    window.onload = function(){
    document.onclick = function(){
    var pY = window.event.clientY;
    var pX = window.event.clientX;
    geraCirculo(pX,pY,250,'Circ1',document.body);
    };
    };

    tudo isso dentro da tag script

    Ponha dentro do head do html

    ResponderExcluir

Resultado! Concursos