Guide 2: Control playback position
Overview
In this guide, we'll show a few common controls that allow users to control the playback of a 3D model animation in the display-3d-model
component. This includes the ability to:
Start playing and pausing a 3D model animation
Moving the playback position forwards or backwards
Setting the playback position to a specified point
The view we'll build will look as follows:

Developer notes:
Please refer to the developer notes in the first guide. The same notes apply to this guide.
Load and display the 3D model in your view
Please refer to this section in the first guide. We'll use the same foundations from the first guide in the below guide.
Play and pause the 3D model animation
To play and/or pause the 3D model animation, we'll add the following buttons to our view XML:
<?xml version="1.0" encoding="UTF-8"?>
<view title="3D Model Viewer">
<var name="animation_file" type="attachment" media="any" />
<var name="scale" type="number" />
<grid column-count="4">
<cell column-span="3">
<display-3d-model
id="example"
bind="animation_file"
scale="scale"
autoplay="false"
material-vertex-groups="false"
/>
</cell>
<cell>
<heading>Playback:</heading>
<button-group>
<button hide-if="$:isPlaying" label="Play" icon="fa-play" on-press="$:playAnimation()" validate="false" />
<button show-if="$:isPlaying" label="Pause" icon="fa-pause" on-press="$:pauseAnimation()" validate="false" />
</button-group>
<heading>Update 3D model:</heading>
<capture-file bind="animation_file" label=".fbx.zip file" downloadable="true" />
</cell>
</grid>
</view>
Note that we have set the autoplay
attribute to false
, since we want users to be able to control the playback manually. We have also added an id
attribute, which is used by component methods to identify the component in the view XML.
In the view JS, we'll initialize a global variable for isPlaying
which is used to dynamically show and hide the play and pause buttons.
var isPlaying = false;
// This function is called when the app navigates to this view (using a link)
function init() {
// initialize any data here that should be available when the view is shown
view.scale = 0.1;
}
Next, we'll need to define the logic for playing and pausing the animation. In the view JS, we'll add two functions and add a playheadPosition
variable to track the elapsed playback time:
var isPlaying = false;
var playheadPosition = 0;
// This function is called when the app navigates to this view (using a link)
function init() {
// initialize any data here that should be available when the view is shown
view.scale = 0.1;
}
// This function is called when the user returns to this view from another view
function resume(from) { }
function playAnimation() {
console.log("Playing animation")
// Set the component's playhead to the specified playhead position
component.display3dModel({ id: "example" }).setPlayhead(playheadPosition);
// Start the animation from the defined playhead
component.display3dModel({ id: "example" }).animationStart();
// Hide the "Play" button and show the "Pause" button
isPlaying = true;
}
function pauseAnimation() {
console.log("Pausing animation")
// Stop playing the animation
component.display3dModel({ id: "example" }).animationStop();
// Show the "Play" button
isPlaying = false;
// Store the current playhead position
playheadPosition = component.display3dModel({ id: "example" }).getPlayhead();
}
Note that the above functions, to start and stop the animation playback, make use of multiple component methods of display-3d-model
.
Move the playhead forwards, backwards or set it to a specific point
Here we are adding controls to move the animation playhead position forwards and backwards by a set amount, as well as directly specifying the playhead position.
We'll update the relevant part of the view XML code to the following:
<?xml version="1.0" encoding="UTF-8"?>
<view title="3D Model Viewer">
...
<grid column-count="4">
<cell column-span="3">
...
</cell>
<cell>
<heading>Playback:</heading>
<button label="Set Time" subtext="Current: {$:timeElapsed}" icon="fa-stopwatch" on-press="$:setPlayhead()" validate="false" />
<button-group>
<button label="Backwards" icon="fa-fast-backward" on-press="$:skipAnimation(-10000)" validate="false" />
<button label="Forward" icon="fa-fast-forward" on-press="$:skipAnimation(10000)" validate="false" />
</button-group>
<button-group>
<button hide-if="$:isPlaying" label="Play" icon="fa-play" on-press="$:playAnimation()" validate="false" />
<button show-if="$:isPlaying" label="Pause" icon="fa-pause" on-press="$:pauseAnimation()" validate="false" />
</button-group>
...
</cell>
</grid>
</view>
In the view JS, we'll define the skipAnimation
and setPlayhead
functions:
function setPlayhead() {
// Allow the user to enter a new position in ms
var position = journey.dialog.input({
title: 'Set Playhead position',
message: "Enter the value in ms",
inputValue: playheadPosition.toString(),
});
if (position != null) {
// Store the new position
playheadPosition = Number(position);
// Show the "Play" button
isPlaying = false;
}
}
function skipAnimation(timeValue) {
// Update the playhead position
playheadPosition = playheadPosition + timeValue;
// Automatically start/continue playing from this new position
playAnimation();
}
Complete view code
Below is the complete View XML and JS code used in this guide:
<?xml version="1.0" encoding="UTF-8"?>
<view title="3D Model Viewer">
<var name="animation_file" type="attachment" media="any" />
<var name="scale" type="number" />
<grid column-count="4">
<cell column-span="3">
<display-3d-model
id="example"
bind="animation_file"
scale="scale"
autoplay="false"
material-vertex-groups="false"
/>
</cell>
<cell>
<heading>Playback:</heading>
<button label="Set Time" subtext="Current: {$:playheadPosition}" icon="fa-stopwatch" on-press="$:setPlayhead()" validate="false" />
<button-group>
<button label="Backwards" icon="fa-fast-backward" on-press="$:skipAnimation(-10000)" validate="false" />
<button label="Forward" icon="fa-fast-forward" on-press="$:skipAnimation(10000)" validate="false" />
</button-group>
<button-group>
<button hide-if="$:isPlaying" label="Play" icon="fa-play" on-press="$:playAnimation()" validate="false" />
<button show-if="$:isPlaying" label="Pause" icon="fa-pause" on-press="$:pauseAnimation()" validate="false" />
</button-group>
<heading>Update 3D model:</heading>
<capture-file bind="animation_file" label=".fbx.zip file" downloadable="true" />
</cell>
</grid>
</view>
var isPlaying = false;
var playheadPosition = 0;
// This function is called when the app navigates to this view (using a link)
function init() {
// initialize any data here that should be available when the view is shown
view.scale = 0.1;
}
// This function is called when the user returns to this view from another view
function resume(from) { }
function setPlayhead() {
// Allow the user to enter a new position in ms
var position = journey.dialog.input({
title: 'Set Playhead position',
message: "Enter the value in ms",
inputValue: playheadPosition.toString(),
});
if (position != null) {
// Store the new position
playheadPosition = Number(position);
// Show the "Play" button
isPlaying = false;
}
}
function skipAnimation(timeValue) {
// Update the playhead position
playheadPosition = playheadPosition + timeValue;
// Automatically start/continue playing from this new position
playAnimation();
}
function playAnimation() {
console.log("Playing animation")
// Set the component's playhead to the specified playhead position
component.display3dModel({ id: "example" }).setPlayhead(playheadPosition);
// Start the animation from the defined playhead
component.display3dModel({ id: "example" }).animationStart();
// Hide the "Play" button and show the "Pause" button
isPlaying = true;
}
function pauseAnimation() {
console.log("Pausing animation")
// Stop playing the animation
component.display3dModel({ id: "example" }).animationStop();
// Show the "Play" button
isPlaying = false;
// Store the current playhead position
playheadPosition = component.display3dModel({ id: "example" }).getPlayhead();
}
Last updated