Create 360 degree turntable animation for 3D renderings with Titanium SDK

Following the color animation tutorial, this post shows how to create turntable animation with Titanium. Turntable animation is a 360° animation in one axis:

and is mostly used to show 3D objects from all sides. Since we cannot use a 3D engine, we will use a prerendered sprite sheet to create our animation. The sprite sheet contains all frames of the 360° animation and is stacked in a grid. The bigger you create the image, the higher the resolution will be; if you create more frames, you will have a smoother animation. In this example, we use a 8×8 grid with a 250x250px frame. So, the full image will be 2000x2000px.

The Alloy setup is rather easy – a View with the whole image and one View around it that displays only one frame: index.xml

<Alloy>
    <Window>
        <View id="frameView">
            <View id="img"/>
        </View>
    </Window>
</Alloy>

index.tss

"#frameView" : {
    width: 250,
    height: 250,
    touchEnabled: false
}
"#img" : {
    width: 2000,
    height: 2000,
    backgroundImage: "/images/turntable.jpg",
    touchEnabled: false,
    top:0,
    left:0
}

The whole logic is inside the controller where we use touchStart/touchMove to cycle through the frames. To do this, we have disabled `touchEnabled` on the two views and add two event listeners to our index window:

function onStart(e) {
}
function onMove(e) {
}

$.index.addEventListener("touchstart", onStart);
$.index.addEventListener("touchmove", onMove);

$.index.open();

Inside onStart, we store the first x coordinate where the user clicks on the screen and calculate the distance to it every time touchmove is called:

var distX = 0;
var sX = 0;
var frame = 0;

function onStart(e) {
    // set start value
    sX = e.x;
}

function onMove(e) {
    // calculate distance between start and current x
    distX = (sX - e.x);
}

$.index.addEventListener("touchstart", onStart);
$.index.addEventListener("touchmove", onMove);

$.index.open();

If we move 5px, we will change a frame and set the start point the the new x coordinate. When we reach frame 64, we have to go to frame 0 again and visa versa so we have an endless loop.

function onMove(e) {
    // calculate distance between start and current x
    distX = (sX - e.x);

    // 5px buffer until we change a frame
    if (distX < -5) {
   	 frame--;
   	 sX = Math.floor(e.x);
    } else if (distX > 5) {
   	 frame++;
   	 sX = Math.floor(e.x);
    }

    // check frame
    if (frame >= 64) {
   	 frame = 0;
    } else if (frame < 0) {
   	 frame = 63;
    }
}

The last thing we need to do is calculate the top and left position of our frame. Frames 1 to 8 are at top=0 and left=0, 250, 500,…. Once we reach frame 9, we will start from left=0 again, but move top one row down (250px). In Javascript, we can do this simply with:

// frame to px
var x = Math.floor((frame * 250) % 2000);
var y = Math.floor((frame * 250) / 2000) * 250;

// change image
$.img.left = -x;
$.img.top = -y;

When you start your app and move your finger from one side to another, you will see a spinning object! The whole index.js looks like this:

var distX = 0;
var sX = 0;
var frame = 0;

function onStart(e) {
    // set start value
    sX = e.x;
}

function onMove(e) {
    // calculate distance between start and current x
    distX = (sX - e.x);

    // 5px buffer until we change a frame
    if (distX < -5) {
   	 frame--;
   	 sX = Math.floor(e.x);
    } else if (distX > 5) {
   	 frame++;
   	 sX = Math.floor(e.x);
    }

    // check frame
    if (frame >= 64) {
   	 frame = 0;
    } else if (frame < 0) {
   	 frame = 63;
    }

    // frame to px
    var x = Math.floor((frame * 250) % 2000);
    var y = Math.floor((frame * 250) / 2000) * 250;

    // change image
    $.img.left = -x;
    $.img.top = -y;
}

$.index.addEventListener("touchstart", onStart);
$.index.addEventListener("touchmove", onMove);

$.index.open();

and you can find the full project at: https://github.com/m1ga/appcelerator_turntable_animation

Like the content?

If you like the tutorials, plug-ins or want to see more please consider becoming a Github sponsor.

Content