Search code examples
javascriptaccelerometermotionevent

JS use DeviceAcceleration.x to pan image seamlessly


I have an image larger than viewport that I'm trying to pan on the x plan according to device Acceleration value.

            _____________________
            |                   |
            |   Device          |
            |                   |
    ________|___________________|__________
    |       |                   |         |
    |       |   Image           |         |
    |       |                   |         |
    |_______|___________________|_________|
            |                   |
            |                   |
            |                   |
            |                   |
            |___________________|


            <-------------------->
                    X axis      

I can get to semi-decent results but nothing like great.

From my understanding I need to :

  • get the acceleration value
  • get the object position
  • combine these two value (maybe with frequency ?)
  • Apply the new position to the object

So far I have something like : (I'm using gyronorm.js so the acceleration data is called data.dm.x)

var accelX = data.dm.x
var currTrans = $('#pano').css('-webkit-transform').split(/[()]/)[1]
var posX = parseInt(currTrans.split(',')[4])
var newPos = posX+accelX
$('#pano').css({'-webkitfr-transform':'translateX('+(newPos)+'px)'})

I feel like I'm missing a core concept here but after hours of research I wasn't able to find it.


Solution

  • The major problem with your code is that you are changing the position of the image by the acceleration, but acceleration is the change in speed over time, so:

    // speed and positionX are declared somewhere else
    speed += accelX
    positionX += speed
    

    ...would be better.

    You are correct that the frequency is relevant, since you would need to do something like:

    // speed and positionX are declared somewhere else
    speed += accelX / frequency
    positionX += speed / frequency * some_number
    

    ... in order to get make everything scale if you were to change the frequency. (some_number is a number used to scale the position so that it moves at the speed to want)

    Unfortunately finding the relative position of a device using only accelerometer data is very difficult since error accumulates over time. The example code above would work if you had a theoretical "perfect accelerometer", but I doubt anyone has a phone with one of those, so the above code doesn't actually solve your problem (see calculating distances using accelerometer).

    I would suggest using the tilt (device orientation) rather than acceleration:

    var translate = 0;
    var pano = $('#pano');
    var frequency = 40;
    var multiplier = 5;
    var gn;
    
    function init_gn() {
        var args = {
          logger: null,
          gravityNormalized: true,
          frequency: frequency
        };
        gn = new GyroNorm();
        gn.init(args).then(start_gn).catch(console.log);
    }
    
    function start_gn() {
        gn.start(gnCallBack);
    }
    
    function gnCallBack(data) {
        var tilt = data.do.gamma; // device orientation
        translate += tilt / frequency * multiplier;
        pano.css('transform', 'translateX(' + translate + 'px)');
    }
    

    This code lets you tilt your phone to the side to pan on the image.