JS use DeviceAcceleration.x to pan image seamlessly
Asked Answered
T

2

7

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.

Triune answered 13/4, 2018 at 14:13 Comment(1)
Can you create a CodePen so we can play around with it?Anthropo
W
2

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.

Wadesworth answered 2/5, 2018 at 14:39 Comment(2)
Thank you for your answer ! I will have time to try this implementation in the next few days I'll keep you updated !Triune
That works wonderfully replacing data.do.gamma with data.dm.beta, thanks A LOT ! I wish I could give you this bounty as it is fully answered.Triune
H
0

You got the core concept right. But your app is probably missing animations to make the repositions look fluently (you don't want your image to jump 50px at once). You can use CSS animations to create a nice fluent transition from the old coordinate to the new coordinate.

Here an easy example how you can animate your transform when re-positioning (cats included) - https://codepen.io/dmonad/pen/aGbbrv

  1. Use css transitions to animate the transform.
  2. Use a transition timing to fine-tune your transition.

Currently your transform also looks like this:

        _____________________
        |                   |
        |   Device          |
        |                   |
        |___________________|__________
        ||                  |         |
        ||  Image           |         |
        ||                  |         |
        ||__________________|_________|
        |                   |
        |                   |
        |                   |
        |                   |
        |___________________|


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

So make sure to position the image in the center (you can also set negative translateX(-500px) values). This is how you can compute the initial value of your image position:

var img = document.querySelector('img')
// width of the image
var imgWidth = img.getBoundingClientRect().width
// width of the container that holds the image
var containerWidth = document.body.clientWidth

var initialPosition = -imgWidth/2 + containerWidth/2
img.style.setProperty('transform', 'translateX(' + initialPosition + 'px)')
Huoh answered 18/4, 2018 at 3:51 Comment(3)
Hi, thanks for this but my question is about integrating the device accelerometer (DeviceMotionEvent.acceleration.x) to use this setup. That is where things become choppy and glitchy.Triune
I jumped to the conclusion that your implementation looks shaky (the image jumps around much). So can you tell us what exactly is not working for you? Because your basic approach is valid, if you want to move the image based on the device movement. What is the end-result you are hoping for?Huoh
See accepted answer, thanks any way for your interest.Triune

© 2022 - 2024 — McMap. All rights reserved.