Artigos com o marcador Javascript
Rede Infinita
31/10/11
Hoje foi ao ar o projeto Rede Infinita baseado no conceito da Unisinos: Infinitas Possibilidades. O projeto criado pela agência Escala e desenvolvido pela Grifo.
O aplicativo tem como objetivo agrupar pessoas com interesses semelhantes – quanto mais próximo você estiver de pessoas como você, mais fácil será se comunicar e trocar informações para criar novas possibilidades para o mundo.
Esse projeto foi desenvolvido em HTML5, onde a funcionalidade mais interessante é a visualização da rede (http://redeinfinita.unisinos.br/user/renatho). Quando iniciamos o projeto, começamos a avaliar qual seria a melhor tecnologia, pois a ferramenta precisa suportar um número muito grande de usuários. A performance dessa visualização era um ponto crítico, devido à lógica envolvida que requer uma série de cálculos em tempo real no cliente.
Iniciamos os testes utilizando SVG e VML, onde teríamos um amplo suporte dos navegadores. Mas quando começamos a cadastrar usuários vimos que a performance ia por água abaixo, pois com VML são criados muitos elementos no DOM. Com mil usuários o navegador já começava a travar.
Nossa próxima tentativa seria utilizar tags <div> para fazer as bolinhas, como muitas ferramentas fazem em gráficos semelhantes a esse. Mas apesar de nada elegante também teríamos muitos elementos no DOM, então nossa segunda tentativa foi testar com canvas, mesmo sem ter bem definido qual seria a solução para o IE7 e 8 que não possuem suporte. Com o canvas ainda enfrentamos certa lentidão por estarmos desenhando as bolinhas com gradient.
Para começar a melhorar a perfomance, resolvemos desenhar as bolinhas como imagem, pois temos uma variação de 6 cores. Dessa forma não precisaríamos montar um objeto para o gradiente a cada usuário cadastrado. Isso melhorou muito a situação. Também fizemos um carregamento “faseado” em 6 tipos de usuários: cada tipo carregando em seu tempo, o que aliviou bastante as iterações do loop que monta o gráfico.
Mas e agora? E o IE? Começamos testando o ExplorerCanvas (que transforma o canvas para VML), mas assim voltávamos à estaca zero não resolvendo o problema. Então resolvemos testar o FlashCanvas e nos surpreendemos com a performance obtida, porém com uma série de bugs. Depois de muito tentar resolver os bugs, nosso desenvolvedor @jcemer resolveu testar a verão PRO e como num passe de mágica todos problemas estavam resolvidos! Valor da versão PRO: US$ 31. A justificativa do valor: “IE” ao contrário.
Este projeto, como todos os projetos da Grifo, contou com a colaboração de todos os desenvolvedores com opiniões e ótimas soluções. Parabéns ao @jcemer, @ricardobeat, @askoth, @vitor42, @mutly, @filipemedina e não menos importante: eu (@renatho) =P .
Input File – Formulários personalizados
23/08/10
Vamos para o último post da série formulários personalizados. Já mostramos como personalizar o campos de radio e checkbox e também as combobox. Hoje iremos mostrar como personalizar um campo de arquivo que é o mais simples.
As duas grandes sacadas para a personalização do input file são as seguintes:
- Utilizaremos o campo com opacidade 0 por cima do campo falso, assim como nos outros casos de personalização de formulário;
- Se você já tentou fazer esse teste, provavelmente teve problemas para aumentar o tamanho do campo conforme o layout que está trabalhando. A forma de fazer isto é aumentando o tamanho da fonte.
Vamos montar um exemplo passo a passo e no final disponibilizaremos o link com o exemplo completo. Não trapaceie, monte o exemplo com suas próprias mãos e depois veja o link.
Começamos pelo HTML:
<div class="inputFile"> <span>Selecione um arquivo</span> <input type="file" name="arquivo" id="arquivo" /> </div>
O span será utilizado para mostrar o nome do arquivo selecionado.
Agora através do CSS vamos posicionar o input sobre o span e ocultá-lo com opacidade. Desta forma, quando o usuário clicar no span (que é o que estará visível), na verdade estará clicando no input.
.inputFile {
width: 185px;
height:40px;
position: relative;
overflow: hidden;
background: red;
}
.inputFile span {
display: block;
position: absolute;
}
.inputFile input {
position: absolute;
right: 0;
z-index: 2;
font-size: 100px; /* Aumenta tamanho do campo */
opacity: 0;
filter: alpha(opacity=0);
}
Note a propriedade font-size: 100px no input. Isto é utilizado para aumentar o tamanho do campo que não respeita as propriedades width e height em alguns browsers.
Agora só falta exibir no span o valor selecionado no input. Isto é feito com poucas linhas utilizando jquery:
$("#arquivo").change(function() {
$(this).prev().html($(this).val());
});
E está pronto. Simples não? Conseguiu se segurar e montar antes de abrir o link de exemplo? Então agora acesse personalização de input file
As técnicas mostradas foram testadas em IE6 e superiores, Firefox 3.6, Chrome e Safari. Qualquer problema que encontrarem em outras versões de browser, mobile ou outros do gênero nos avisem para tentarmos aprimorar a técnica. Sugestões de melhoria também são bem-vindas.
Abraços e até a próxima!
Solucionando o Code Golf + Maratona IG com Javascript
27/07/10
Semana passada Porto Alegre recebeu o FISL, que reuniu mais de 8 mil pessoas no campus da PUC. Estivemos lá pra conferir as palestras envolvendo HTML5, CSS, Javascript, acessibilidade e novas tecnologias/projetos.
No meio tempo entre trabalho e palestras resolvi participar do Code Golf do IG: resolver os 5 problemas dados com o menor código possível. O ganhador de cada categoria levou um iPod touch. Já que Javascript não era um opção, foi PHP mesmo. Depois de uma disputa acirrada e de ter ficado em segundo lugar até meia hora antes do final, a pontuação foi atualizada e acabei terminando em primeiro lugar :]
Neste post vamos ver como ficaram as soluções em PHP, e também em Javascript. Pra isso vamos utilizar o JSDB, que interpreta Javascript usando a engine SpiderMonkey da Mozilla e nos dá acesso ao sistema de arquivos, DBs e web. Roda em Linux, Mac e Windows e não exige instalação, é só baixar, descompactar e começar a usar. Vamos resolver também o problema da Maratona IG em menos de 15 minutos usando Javascript.
Vamos ao código:
Questão 1
Dado o número de iterações exibir a sequência de Fibonacci até aquela iteração
entrada: 6
saida: 1, 1, 2, 3, 5, 8
PHP
Esse foi o código final (pra economizar espaço, colocamos tudo dentro de um for loop):
<?php for($a=$c=0,$b=1;$c<$argv[1]; $x=$a,$a=$b,$b+=$x)echo(!$c++?'':', ').$b;
Começamos com 0 e 1 e somamos o último com o anterior até atingir o número de iterações. Em PHP é impossível fazer isso sem utilizar uma terceira variável. A solução mais simples em Javascript é utilizar um array:
Javascript
var
a = 0,
b = 1,
i = 0,
numeros = [1];
while(++i < jsArguments[0])
{
numeros.push( b=a+(a=b) );
// isto é possível porque a variável "a" à esquerda
// da expressão (a=b) continua com o valor antigo,
// o que não acontece no PHP
}
writeln(o);
// $ ./jsdb q1.js 6 > 1, 1, 2, 3, 5, 8
Deixando o array – e a legibilidade do código – de lado, o resultado final é um pouco mais compacto:
for(a=c=b=1;c++<=jsArguments[0];print((b=a+(a=b))-a+' '));
Questão 2
Dado uma frase retornar se é um palíndrome ou não e listar os caracteres em ordem decrescente de número de incidências na mesma
entrada: “A mala nada na lama”
saída:
Palíndrome
8 a
2 m
2 n
2 l
1 d
PHP
As funções count_chars e strrev tornam o trabalho fácil:
<?php $s=str_replace(' ','',$argv[1]);
echo($s!=strrev($s)?"Não é ":"")."Palíndrome";$c=count_chars($s,1);
arsort($c);foreach($c as $i=>$v)echo"\n$v ".chr($i);
Javascript
Já em Javascript a coisa é mais complicada. O método reverse() só existe para arrays. Temos que fazer a inversão da string e a contagem por nossa conta:
// removemos espaços e outros caracteres da string
var str=jsArguments[0].toLowerCase().replace(/\W/g,'');
// verificamos se o inverso é igual
println( (str!=str.split('').reverse().join('') ? "Não é " : "")+"Palíndrome");
// contamos os caracteres usando um array
var chars = [];
for(var i in str){ // não façam isso em casa
var key = str[i];
chars[key] = chars[key]+1 || 1;
}
// exibimos a contagem pra cada letra
for(var n in chars){
println(chars[n]+" "+n);
}
E depois transformamos de novo isso tudo em uma linha ininteligível:
s=jsArguments[0].toLowerCase().replace(/\W/g,'');
println((s!=s.split('').reverse().join('')?"Não é ":"")+"Palíndrome");
c=[];for(i in s){k=s[i];c[k]=c[k]+1||1;}for(n in c)println(c[n]+" "+n);
Questão 3
Dado um endereço IP e uma máscara de rede, retornar o endereço de broadcast e a conotação CIDR da rede
entrada: 201.94.10.19 255.255.255.0
saída: 201.94.10.255 /24
Essa é assustadora. Mas depois de consultar a Wikipedia sobre o assunto se descobre que a matemática é simples, e que CIDR é uma gambiarra que inventaram pra usar um mesmo IP em mais de uma máquina, em redes internas. Temos que fazer o seguinte:
- Descobrir o complemento de cada pedaço da subnet mask (255.255.255.0), no caso do exemplo 0.0.0.255
- Aplicar o operador bitwise OR à cada parte do IP e o complemento da máscara (ex: 255|0)
O resultado disso é o endereço de broadcast. Depois, precisamos transformar o IP resultante em binário, e contar quantos bits “1″ ele contém. Essa é a conotação CIDR. Vamos ao código:
PHP
<?php $b='';$c=0;$m=explode(".",$argv[2]);
foreach(explode('.',$argv[1]) as $k=>$v){$b.=($k?'.':'').($v|255-$m[$k]);
$c+=substr_count(decbin($m[$k]),1);}echo "$b /$c";
Javascript
var
cidr = 0,
ip = jsArguments[0].split('.'),
mask = jsArguments[1].split('.');
// encontramos o broadcast address
// usando a fórmula descrita
var broadcast = ip.map(function(val,key){
return val | (255-mask[key]);
}).join('.');
// e calculamos o CIDR por partes
mask.forEach(function(val){
// primeiro convertemos o valor para Number
// e depois para string usando base 2 (binário)
// ex: 252 > 11111100
// e então contamos quantos "1"s na string
cidr += (+val).toString(2).split('1').length-1;
});
//saida
writeln(broadcast+" /"+cidr);
O resultado final é muito mais longo do que em PHP pelas várias chamadas de função, mas ainda pode ser reduzido:
c=0;i=jsArguments[0].split('.');m=jsArguments[1].split('.');
b=i.map(function(v,k){return v|(255-m[k])}).join('.');
m.forEach(function(v){c+=(+v).toString(2).split('1').length-1});
writeln(broadcast+" /"+cidr);
Questão 4
Dados dois números naturais m e n e duas sequências ordenadas com m e n números inteiros, obter uma única sequência ordenada contendo todos os elementos das sequências originais sem repetição
entrada: 1,5,6,10,12 2,5,9,29
saída: 1, 2, 5, 6, 9, 10, 12, 29
Mais uma vez as funções nativas do PHP fazem todo o trabalho. Em Javascript é mais divertido.
PHP
<?php $a=array_unique(explode(',',$argv[1].','.$argv[2]));
sort($a);echo implode(',',$a);
Javascript
var
resultado = [],
a1 = jsArguments[0].split(',')
a2 = jsArguments[1].split(','),
arr = a1.concat(a2);
// inserir valor em unique somente se
// ainda não existe valor igual no array
arr.map(function(val){
if (resultado.indexOf(+val)<0)
resultado.push(+val);
})
// pôr em ordem numérica (asc)
resultado = resultado.sort(function(a,b){
return a>b;
});
writeln(unique);
// saída:
// $ ./jsdb q4.js 1,4,2,5,6 1,2,6,3
// 1, 2, 3, 4, 5, 6
Dá pra pular algumas etapas pra encolher o código:
u=[];a=jsArguments.join().split(',');
a.map(function(v){u.indexOf(+v)<0&&u.push(+v)});
u=u.sort(function(a,b){return a>b});writeln(u);
Questão 5
Escreva uma função que recebe uma matriz de caracteres 8×8 representando um tabuleiro de xadrez e calcula o valor total das peças do jogo. Espaços vazios do tabuleiro são codificados como casas com ‘v’ e têm valor 0 (zero). O valor das demais peças é dado de acordo com a tabela: Peão (p): 1, Cavalo (c): 3, Bispo (b): 3, Torre (t): 5, Rainha (a): 10, Rei (r): 50, Vazio: (v)
entrada:
tcbarbct
pppppppp
vvvvvvvv
vvvvvvvv
vvvvvvvv
vvvvvvvv
pppppppp
tcbarbct
saída: 180
Não se preocupe com a idéia do tabuleiro, só precisamos traduzir o valor de cada caractere válido na string e ignorar o resto. Solução simples: fazer um loop com todos os caracteres e usar como chave pra buscar no array de valores. Em PHP nem isso precisa, a função count_chars() já faz a contagem:
PHP
<?php $s=0;$v=Array('p'=>1,'c'=>3,'b'=>3,'t'=>5,'a'=>10,'r'=>50,'v'=>0);
foreach(count_chars(preg_replace('/\W/','',$argv[1]),1) as $c=>$n){
$s+=$v[chr($c)]*$n;};echo$s;
Javascript
var
valores = { p:1, c:3, b:3, t:5, a:10, r:50 },
// remover todos os caractere não alfanuméricos
pecas = jsArguments[0].replace(/\W/g,''),
pontos = 0;
for(var i in pecas){
pontos += valores[ pecas[i] ] || 0;
}
writeln(pontos);
E a versão condensada, usando o método replace() para o loop:
v={p:1,c:3,b:3,t:5,a:10,r:50};p=jsArguments[c=0].replace(/\w/g,function(a){c+=v[a]||0});writeln(c);
Maratona IG
O desafio da Maratona era o seguinte: a partir de um arquivo texto de 57Mb contendo tweets em JSON, fazer a contagem dos tweets contendo sentimentos “positivos” ou “negativos”. A contagem com a menor margem de erro vence. O problema maior aqui é deduzir qual o tipo de filtro utilizado como referência.
Uma olhada rápida no arquivo de dados nos mostra que as mensagens variam entre os termos feliz/amo/adoro e triste/odeio. Isso é tudo que precisamos saber, agora basta uma expressão regular. Como a chance de uma das palavras-chave aparecer em qualquer outro lugar do objeto é praticamente nula, nem precisamos interpretar o JSON.
var
positivo = /feliz|gosto|gostei|amo|amei|adoro|adorei/i,
negativo = /triste|odeio|odiei/i,
p = 0,
n = 0,
line, tweets;
// carregamos o arquivo como Stream
tweets = new Stream(jsArguments[0], 'rt');
// e lemos linha por linha
while (line = tweets.readLine())
{
if(negativo.test(line))
n++;
else if(positivo.test(line))
p++;
}
writeln("Tweets Positivos:"+p);
writeln("Tweets Negativos:"+n);
writeln("Tweets Negativos:"+n);
E temos o resultado:
Tweets Positivos: 35507
Tweets Negativos: 4307
Pelo resultado da maratona podemos calcular os números ideais:
Positivos: 35322
Negativos: 4316
A margem de erro do código acima é de 0.005% e 0.003% (positivos/negativos), e o código foi desenvolvido em menos de 15 minutos. A execução também é muito rápida, leva pouco mais de 5 segundos, e isso com SpiderMonkey que não é das engines JS mais rápidas.
O prêmio que a dupla vencedora levou: dois iPads.
Encontrou algum bug no código ou sabe de uma maneira melhor? Também acha que javascript deve ser uma opção nesse tipo de competição? Deixe um comentário abaixo.
Combobox – Formulários personalizados
01/07/10
Dando sequencia à série de Posts de formulários personalizados, hoje falaremos do combobox (select). Esta é outra técnica que não perde acessibilidade, não perde usabilidade e utiliza javascript não-obstrutivo.
O resultado final do que explicaremos aqui será um select oculto com um span o sobrepondo e exibindo o valor. Ao clicar no select as opções dele são exibidas normalmente da forma nativa.
O único problema desta técnica é que não funciona no IE6 (segundo o Jeremias: “IE IE IE é safado tem q morrer“), pois ele (browser burro) não suporta opacidade no select, então para IE6 podemos apenas colocar uma cor de fundo no select para não destoar muito do desenho – Isto chama-se Graceful Degradation (que por sinal também merece um futuro Post).
Como é de praxe, começamos pelo HTML:
<div class="styleCombobox">
<select title="Selecione">
<option value="1">Opção 1</option>
<option value="2">Opção 2</option>
<option value="3">Opção 3</option>
</select>
</div>
Utilizamos uma div encapsulando o select, pois através do script vamos inserir um span antes do select exibindo o valor selecionado. No atributo title podemos inserir um valor inicial (valor que não precisa aparecer nas opções da combobox – ex.: “Selecione uma opção”).
Agora vamos criar um CSS para os estilos da nossa combobox conforme o desenho. No nosso exemplo colocaremos apenas um background cinza para não sair do foco do post.
Além dos estilos do desenho, vamos deixar o select sem opacidade – Os browsers ocultam somente a parte do valor do select, então quando clicarmos nele as opções serão exibidas.
.styleCombobox {
width:200px;
background:gray;
}
.styleCombobox span {
position:absolute;
}
.styleCombobox select {
width:100%;
opacity:0;
filter:alpha(opacity=0);
}
No script que estamos disponilibizando também colocamos a funcionalidade de foco para o select, então precisamos criar outro estilo para ele:
.comboboxFocus {
border:dotted 1px #CCC;
}
Como comentado no início do post, no caso do IE6 você pode criar hacks para alterar as cores do select para ficar mais próximo do desenho, mas não entraremos no mérito.
Agora você precisa baixar o plugin desenvolvido pela Grifo neste link styleCombobox e importá-lo na sua página. A chamada fica dessa forma:
<script type="text/javascript">
$(".styleCombobox select").styleCombobox({
classFocus:"comboboxFocus"
});
</script>
Para usuários com javascript desabilitado, vamos exibir os selects normais do browser com o noscript:
<noscript>
<style type="text/css">
.styleCombobox select {
filter:alpha(opacity=1);
opacity:1;
}
</style>
</noscript>
As técnicas mostradas foram testadas em IE6 (apesar de neste funcionar parcialmente) e superiores, Firefox 3.6, Chrome e Safari. Qualquer problema que encontrarem em outras versões de browser, mobile ou outros do gênero nos avisem para tentarmos aprimorar a técnica. Sugestões de melhoria também são bem-vindas.
Veja um exemplo de personalização de combobox em funcionamento.
Abraços e até a próxima!
Radio e Checkbox – Formulários personalizados
25/06/10
Neste post vou dar umas dicas de como personalizar campos de Radio e Checkbox, afinal os designers adoram nos sacanear. Quando terminar de ler aposto que você vai falar “como não pensei nisso antes?”, pois a solução além de super simples e óbvia, não perde acessibilidade, não perde usabilidade e foram utilizadas técnicas de javascript não-obstrutivo.
Você já deve saber o clique em um label que referencia algum campo (Ex.: <label for="idDoCampo">) tem a função de foco para este campo. E no caso dos checkbox e radios a função é o clique do campo (marcar / desmarcar). Esta é a essência da solução. Já começou cair a ficha né?
Nosso HTML será composto por uma label que encapsula o input e o texto, desta forma tudo que estiver dentro do label estará na área clicável.
Veja o código:
<label for="radioButton1"><input type="radio" name="radioButton" id="radioButton1" /> Radio 1</label> <label for="radioButton2"><input type="radio" name="radioButton" id="radioButton2" /> Radio 2</label> <label for="checkbox1"><input type="checkbox" name="checkbox" id="checkbox1" /> Checkbox 1</label></div> <label for="checkbox2"><input type="checkbox" name="checkbox" id="checkbox2" /> Checkbox 2</label></div>
Através do CSS vamos ocultar os inputs e fazer a personalização sacana que o designer desenhou.
.styleRadio input, .styleCheckbox input {
cursor:pointer;
filter:alpha(opacity=0);
opacity:0;
}
.styleRadio, .styleCheckbox {
cursor:pointer;
height:30px;
background:url(controls.gif) no-repeat;
}
.styleRadio {
background-position:0 -500px;
}
.styleCheckbox {
background-position:0 0;
}
Beleza! já tá funcionando, não está vendo ainda? Usuários cegos já, pois o código está acessível.
Ok, vamos deixar acessível sem screen reader também. Para isso a Grifo fez um plugin do jquery exclusivamente para você, leitor do nosso blog. O plugin pode ser baixado neste link: styleRadioCheckbox.
O plugin trabalha com a estrutura HTML que citamos acima. Você precisará criar 2 classes além da classe para estado normal dos inputs: uma classe para ele marcado e outra para o foco.
Exemplo:
.inputRadioChecked {
background-position:-500px -500px;
}
.inputCheckboxChecked {
background-position:-500px 0;
}
.inputFocus { /* Este está genérico nos para radio e checkbox, mas também pode ser uma classe para cada */
border:dotted 1px #CCC;
}
Agora só falta a chamada do plugin, onde passaremos por parâmetro as classes de estados criadas no passo anterior.
Código de chamada do plugin:
$("input:checkbox").styleRadioCheckbox({
classChecked:"inputCheckboxChecked",
classFocus:"inputFocus"
});
$("input:radio").styleRadioCheckbox({
classChecked:"inputRadioChecked",
classFocus:"inputFocus"
});
Pronto. Agora tudo está funcionando! Mas espere aí, no início do post não dizia que a técnica era feita com javascript não-obstrutivo? Desativando o javascript não está funcionando. – Pergunta pro usuário cego se não está funcionando, aposto que pra ele tá que é uma beleza. Mas ok, vamos achar uma solução para ficar acessível sem screen reader de novo.
Para solucionar este problema iremos inserir uma tag noscript que vai exibir os inputs novamente:
<noscript>
<style type="text/css">
.styleCheckbox input, .styleRadio input {
filter:alpha(opacity=1);
opacity:1;
}
</style>
</noscript>
As técnicas mostradas foram testadas em IE6 e superiores, Firefox 3.6, Chrome e Safari. Qualquer problema que encontrarem em outras versões de browser, mobile ou outros do gênero nos avisem para tentarmos aprimorar a técnica. Sugestões de melhoria também são bem-vindas.
Veja um exemplo de personalização de radio e checkbox em funcionamento.
Abraços e até a próxima!

