Brincando com o Acelerômetro

Trabalha com desenvolvimento web há mais de 12 anos, atuando com projetos open source, palestrante, instrutor, e sócio fundador da Nasc, além de ser curador e idealizador da ​BrazilJS. Também um GDE.

Diversos devices como celulares (praticamente todos os smartphones) e boa parte dos notebooks modernos, já contam com o acelerômetro.

O acelerômetro é a parte responsável por identificar a posição ou giro do aparelho. É o que grande parte de nossos joguinhos usa, pelo SO do aparelho, ou por apps que exibem algo diferente conforme usamos o dispositivo deitado ou em pé.

Agora podemos ter acesso às informações deste sensor, também no browser!

Veja quais os browsers que suportam a API para lidar com o Acelerômetro no site do caniuse.

Suporte ao acelerômetro, no caniuse

Mas não se engane, o funcionamento pode variar um pouco entre um browser e outro.

Hora do demo

Um demo/exemplo é sempre uma boa forma de explicar e entender algo! Por isto criei este demo, que utiliza do acelerômetro para animar um elemento no HTML utilizando CSS. Veja o exemplo

O código fonte está disponível no github.

Se não conseguiu rodar o demo por que seu notebook ou celular não tem acelerômetro, assista este vídeo:

Note que o balão se movimenta tanto para esquerda e direita, quanto para frente e para trás.

Uma coisa que reparei é que alguns aparelhos de celular passam as informações de graus um pouco diferentes, ligeiramente “descalibradas”.

Event Listener

A chave aqui, é utilizar o evento deviceorientation, para sabermos sobre as alterações no sensor do acelerômetro:

js
window.addEventListener("deviceorientation", handleOrientation, true);

A nossa função handleOrientation receberá, por sua vez, o próprio evento:

function handleOrientation(event) {
    // usamos o evento, aqui
}

Uma maneira interessante de detectarmos se o dispositivo/navegador tem suporte ao evento, é:

var hasSupport = 'DeviceOrientationEvent' in window;

NOTA: No Firefox (estou na versão 42), o retorno desta verificação é `true`, o navegador informa que dá suporte, mas o evento nunca é chamado no notebook, apenas no celular! E ainda assim, os graus do movimento em _gamma_ nunca eram recebidos.

O evento

O objeto event que receberemos em nossa função possui as seguintes propriedades:

  • absolute: Se true, o dispositivo utiliza a orientação da própria Terra como fonte de informação para a orientação. Caso false, o dispositivo utiliza de alguma outra fonte de referência, internamente(no próprio aparelho).
  • alpha: Representado por graus, com valores entre 0 e 360, em torno do eixo Z.
  • beta: Rotação em torno do eixo X, também em graus, mas indo de -180 a 180.
  • gamma: Movimento em relação ao eixo Y, também em graus, mas em um range de -90 a 90.

Tudo em uma imagem, seria algo mais ou menos assim: Orientação e giro do acelerômetro

Vê o α, o β e o γ, ali? Entendeu agora por que não é simplesmente “x”, “y” e “z”?

Acho que esta outra imagem ilustra ainda melhor: Animação da rotação e posicionamento

Note que para todos os casos, há um “frame“, um quadro inicial, utilizado como base. Há algumas curiosidades sobre isto, como por exemplo o fato de o Safari tratar o ponto inicial como a posição em que o dispositivo estava no momento em que o evento começou a ser escutado, enquanto outros browsers usam o norte do planeta Terra como referência.

Na própria documentação da W3C, há algumas imagens que tentam explicar isto também (apesar de serem umas imagens meio esquisitas, de celulares “achatados”, acho que valem a ilustração):

![w3c alpha example](/wp-content/uploads/2016/04/w3c-orientation-2.png) ![w3c beta example](/wp-content/uploads/2016/04/w3c-orientation-3.png) ![w3c gamma example](/wp-content/uploads/2016/04/w3c-orientation-4.png)

Tratando os eventos

Para o demo do balão, todavia, há um problema! O evento é disparado a qualquer movimentação, mínima que seja! Veja o exemplo dado no site da MDN, enquanto meu notebook estava completamente parado em cima de uma mesa:

Exemplo de acelerômetro

Por este motivo, eu criei uma variável que esperaria por uma variação mínima, caso contrário, o balão ficaria se movimentando em excesso!

Para causar um efeito ainda mais realístico, adicionei um efeito “whiplash” no balão. Ele não irá simplesmente se mover até a próxima posição, mas sim, passar por ela e voltar um pouco, para que ficasse mais natural…o efeito “chicote”.

Efeito chicote no movimento do balão

O interessante é que para movimentar o balão, me bastou jogar os próprios graus vindos do acelerômetro, para o CSS do elemento, utilizando o transform: rotateZ, afinal de contas, sabemos que os valores para gamma vão de -90 a 90. Eu multipliquei este valor por -1, pois o balão deveria ir para a direção oposta do movimento do dispositivo.

balloon.style.transform = "rotateZ(" + (-1*gamma) + "deg)";

Já para aproximar o balão quando o movimento fosse para trás, e afastá-lo quando o movimento fosse para frente, eu simplesmente peguei o próprio tamanho do balão e subtraí o valor vindo em beta (de -180 a 180).

Notaram que o cordão do balão também faz uma curva?

Para isto, eu adicionei um efeito de border-radius: 50% a ele, um elemento de apenas 3px de largura, com uma borda em uma das laterais. Ou seja, ele é um círculo! Na verdade, uma elipse muito oval com borda apenas em um de seus lados. Tudo o que faço é definir qual dos lados terá a borda, e mexer um pouco na largura deste elemento, para que a linha faça o efeito de curva.

Leituras posteriores

Espero que tenham gostado. Façam alguns experimentos e coloquem os links nos comentários!

Alguns links interessantes para uma leitura posterior:


BrazilJS é uma iniciativa NASC