martes, 27 de mayo de 2014

Plugin para el acelerómetro

El acelerómetro es un elemento que detecta cambios en movimientos relativos en la orientación del dispositivo, en los ejes x, y, z. En otras palabras, mide la aceleración bajo el efecto de la gravedad. En este apartado vamos a conocer el plugin que nos permite acceder al acelerómetro del dispositivo.

fuente: http://w3c.github.io/deviceorientation/start.png


Este plugin se llama device-motion es compatible con las principales plataformas actuales, por lo que no habrá problemas de compatibilidad si lo implementamos en nuestras aplicaciones. Es soportado para:

  • Amazon Fire OS
  • Android
  • BlackBerry 10
  • Firefox OS
  • iOS
  • Tizen
  • Windows Phone 7 and 8
  • Windows 8
Métodos

Disponemos de tres métodos principales:

  • navigator.accelerometer.getCurrentAcceleration(accelerometerSuccess, accelerometerError);
Este método obtiene la aceleración en los ejes x y z, y los valores son enviados a la función callback accelerometerSuccess.
  • navigator.accelerometer.watchAcceleration
Con este método obtenemos la aceleración en un intervalo regular de tiempo. Veamos un ejemplo de uso:

var watchID = navigator.accelerometer.watchAcceleration(accelerometerSuccess, accelerometerError, [accelerometerOptions]);

En watchID guardamos una referencia al muestreo por intervalos de watchAccerelarion. Si todo va bien lanzamos la función accelerometerSuccess(se le pasa el objeto Acceleration como parámetro, explicado a continuación), en caso contrario, la función accelerometerError. AccelerometerOptions es un objeto en el que podremos incluir el siguiente parámetro, a modo de opción: frequency. Este valor se lo podemos pasar expresado en milisegundos(por defecto vale 10000) e identifica el intervalo de muestreo.

  • navigator.accelerometer.clearWatch
Detiene el muestreo de la aceleración que estaba referenciado por watchID. Su uso sería:
navigator.accelerometer.clearWatch(watchID);

Objetos

Tenemos el objeto Acceleration, que es pasado como parámetro en la función accelerometerSuccess, o onSuccess, o como queramos llamarla. Contiene los datos capturados por el acelerómetro en un momento determinado de tiempo. 
El objeto Acceleration tiene tres propiedades, x, y y z, que expresan los valores numéricos de la aceleración en cada eje (en m/s^2). Y también timestamp, que es el tiempo del instante de captura expresado en milisegundos.
Incluye el efecto de la gravedad(9.81 m/s^2), por lo que si el dispositivo yace boca arriba en una superficie horizontal los valores x,y,z serían 0,0, 9.81.

Ejemplo

Partimos del proyecto esqueleto que ya teníamos preparado en apartados anteriores. Lo copiamos y modificamos algunos valores en el fichero de configuración config.xml, básicamente para que no se vea "esqueleto" en el icono de la app en el móvil, cuando vayamos a ejecutarlo.


A continuación ejecutamos la orden que nos instala el plugin en nuestra carpeta de proyecto:
Phonegap plugin add org.apache.cordova.device-motion

Y ya tenemos el acelerómetro accesible desde nuestra aplicación. 

Vamos a implementar una aplicación simple que nos informa cada segundo (1000 milisegundos) de la aceleración en los tres ejes.

El contenido del body del html es el siguiente:
<div class="container">
            <h1 class="text-center">Acelerometro</h1>
            <div class="well">
                <div id="ejeX">
                    
                </div>
                <div id="ejeY">
                    
                </div>
                <div id="ejeZ">
                    
                </div>
            </div>
</div>
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
        <script type="text/javascript" src="./js/jquery-1.11.0.min.js"></script>
        <script type="text/javascript" src="./js/bootstrap.min.js"></script>
        <script type="text/javascript" src="./js/fastclick.js"></script>
        <script type="text/javascript" src="./js/index.js"></script>
        <script type="text/javascript">
            window.addEventListener('load', function() {
                new FastClick(document.body);
            }, false);
            app.initialize();
</script>

He ignorado las líneas de los scripts. Como vemos se muestran 3 divs donde informaremos con javascript de las aceleraciones.

Este es el contenido del fichero javascript:
var app = {
    // Application Constructor
    initialize: function() {
        this.bindEvents();
    },
    // Bind Event Listeners
    //
    // Bind any events that are required on startup. Common events are:
    // 'load', 'deviceready', 'offline', and 'online'.
    bindEvents: function() {
        document.addEventListener('deviceready', this.onDeviceReady, false);
    },
    // deviceready Event Handler
    //
    // The scope of 'this' is the event. In order to call the 'receivedEvent'
    // function, we must explicity call 'app.receivedEvent(...);'
    onDeviceReady: function() {
        app.receivedEvent('deviceready');
    },
    // Update DOM on a Received Event
    receivedEvent: function(id) {
        //iniciamos el muestreo
        //si hay exito, lanzamos la funcion mostrar
        //si hay error, lanzamos la funcion error
        //le pasamos el tiempo de muestreo en un objeto, como tercer parametro
        watchID = navigator.accelerometer.watchAcceleration(mostrar, error, {frequency: 1000});

        //función con la que muestro las aceleraciones
        //accedo al objeto Acceleration, concretamente a sus propiedades
        function mostrar(acceleration){
            $("#ejeX").html("Acceleration X: " + acceleration.x);
            $("#ejeY").html("Acceleration y: " + acceleration.y);
            $("#ejeZ").html("Acceleration z: " + acceleration.z);
        }

        //funcion error que dios quiera que no se ejecute
        function error() {
            alert('error!!');
        };
    }
};

Así luce la aplicación una vez compilada y ejecutada en nuestro terminal

Ejemplo 2

Lo correcto más bien sería decir "mejora del ejercicio anterior", ya que tomamos como base el ejemplo ya realizado y jugamos un poco con los datos que nos da el acelerómetro.
Vamos a implementar un objeto dentro de una caja que "se deje caer" según como tengamos orientado el teléfono(o tablet, o dispositivo compatible, en definitiva).
Añadimos los siguientes div debajo de los tres que ya teníamos:

<div id="caja">
                    <div id="punto">
                        
                    </div>
</div>

Con CSS vamos a hacer que se muestren como una caja y un punto(puntazo, para ser exactos).

#punto{
    width:50px;
    height:50px;
    background-color:black;
    position:absolute;
    top:0;
    left:0;
}

#caja{
    margin:10px auto;
    width:200px;
    height:200px;
    border:1px solid black;
    position:relative;

}



Ahora vamos a capturar esos div con javascript y a aplicar la función animate de jquery:

var app = {
    // Application Constructor
    initialize: function() {
        this.bindEvents();
    },
    // Bind Event Listeners
    //
    // Bind any events that are required on startup. Common events are:
    // 'load', 'deviceready', 'offline', and 'online'.
    bindEvents: function() {
        document.addEventListener('deviceready', this.onDeviceReady, false);
    },
    // deviceready Event Handler
    //
    // The scope of 'this' is the event. In order to call the 'receivedEvent'
    // function, we must explicity call 'app.receivedEvent(...);'
    onDeviceReady: function() {
        app.receivedEvent('deviceready');
    },
    // Update DOM on a Received Event
    receivedEvent: function(id) {
        //iniciamos el muestreo
        //si hay exito, lanzamos la funcion mostrar
        //si hay error, lanzamos la funcion error
        //le pasamos el tiempo de muestreo en un objeto, como tercer parametro
        watchID = navigator.accelerometer.watchAcceleration(mostrar, error, {frequency: 200});

        //función con la que muestro las aceleraciones
        //accedo al objeto Acceleration, concretamente a sus propiedades
        function mostrar(acceleration){
            $("#ejeX").html("Acceleration X: " + acceleration.x);
            $("#ejeY").html("Acceleration y: " + acceleration.y);
            $("#ejeZ").html("Acceleration z: " + acceleration.z);

            //cargo en variables la caja, el punto móvil y los datos que me interesan
            var puntoMovil = $('#punto');
            var limite = $('#caja');
            var posicionPunto = puntoMovil.position();
            var bordeIzquierdo = 0;
            var bordeTop = 0;
            var bordeDerecho = limite.width() - puntoMovil.width() - 10; // 10 represents the 10px for the margin
            var bordeBottom = limite.height() - puntoMovil.height() - 10; // 10 represents the 10px for the margin
            
            //según los datos del acelerómetro muevo el punto a la derecha o izquierda, arriba o abajo
            //con CSS
            if( acceleration.x < -2 && posicionPunto.left <= bordeDerecho ) {
                puntoMovil.animate({
                    left:'+=10'
                },100);
            } else if( acceleration.x > 2 && posicionPunto.left > bordeIzquierdo ) {
                puntoMovil.animate({
                    left:'-=10'
                },100);
            }
            if( acceleration.y < -2 && posicionPunto.top > bordeTop ) {
                puntoMovil.animate({
                    top:'-=10'
                },100);
            } else if(acceleration.y > 2 && posicionPunto.top <= bordeBottom ) {
                puntoMovil.animate({
                    top:'+=10'
                },100);
            }
        }

        //funcion error que dios quiera que no se ejecute
        function error() {
            alert('error!!');
        };
    }

};

He cambiado la opción frequency a 200 milisegundos para que se vea más fluido el movimiento del cuadrado en la caja. También podemos observar que para que el cuadrado negro se mueva, los valores de los ejer x e y tienen que ser mayores que 2 o menores que -2, por lo que si dejamos el dispositivo "más o menos" plano, impediremos que se mueva.

Así se ve la aplicación después de compilar, ejecutar en un teléfono y tenerlo ligeramente inclinado hacia la derecha y hacia arriba:


No hay comentarios:

Publicar un comentario