PERPETUAL MOTION (OR NOT)

The animation settings property for an object in Adobe InDesign has two properties that determine the number of times an animation sequence will repeat:

  • plays(integer) The number of times this animation plays. Can return integer (1-100)
  • plays loop (boolean) Set to true if the animation repeats.

We can see how this works with a few simple scripts. But first we will need a document with an object to animate.

CREATE DOCUMENT

The document will be 1024 px by 768 px set up for Web Intent, 1 page without a Primary Text Frame

In the document, manually create a rectangle 200 px wide and 60 px high, with a colorful fill. Place it near the right side of the page.
Name the object “wagonBase.” You can name your page items using a handy script, or open the Layers panel and physically name the items there.

ANIMATE THE OBJECT

For the animation we will bring the object in from the left side of the page to its current location. For this you can use the following:

toCurrentLocation (AppleScript)

set numTimes to 1 --number of times to animate
set dTravel to 1030 --distance to travel
set dTime to 3.0 --animation duration
set tOffsets to {1, 0.5} --object translation offset point
tell application "Adobe InDesign CC 2017"
   set spreadRef to spread 1 of document 1
   set groupRef to page item "wagonBase" of spreadRef
   my toCurrentLocation(groupRef, dTime, dTravel, numTimes, tOffsets)
end tell

(*Animates object along horizontal path using motion path points*)
on toCurrentLocation(objRef, dTime, dTravel, numTimes, tOffsets)
   --default List of lists for straight line path
   set mPathPoints to {{{{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}, ¬
   {{dTravel, 0.0}, {dTravel, 0.0}, {dTravel, 0.0}}}, true}
   tell application "Adobe InDesign CC 2017"
	tell animation settings of objRef
	   set duration to dTime
	   set design option to to current location
	   set motion path points to mPathPoints
	   set transform offsets to tOffsets
	   if numTimes < 0 then
              set plays loop to true
	   else
	      set plays loop to false
	      set plays to numTimes
	   end if
	end tell
   end tell
end toCurrentLocation

toCurrentLocation (JavaScript)

var numTimes = 1; //number of times to animate
var dTravel = 1030; //distance to travel
var dTime = 3.0 //duration of animation
var tOffsets = [1, 0.5]; //object translation offset point
var spreadRef = app.documents.item(0).spreads.item(0);
var groupRef = spreadRef.pageItems.itemByName("wagonBase");
toCurrentLocation(groupRef, dTime, dTravel, numTimes, tOffsets);

function toCurrentLocation(objRef, dTime, dTravel, numTimes, tOffsets) {
    var mPathPoints = [[[[0.0, 0.0], [0.0, 0.0], [0.0, 0.0]], 
    [[dTravel, 0.0], [dTravel, 0.0], [dTravel, 0.0]]], true];
    objRef.animationSettings.duration = dTime;
    objRef.animationSettings.designOption = DesignOptions.TO_CURRENT_LOCATION ;
    objRef.animationSettings.motionPathPoints = mPathPoints;
    objRef.animationSettings.transformOffsets = tOffsets;
    if (numTimes < 0) {
       objRef.animationSettings.playsLoop = true;
    } else {
       objRef.animationSettings.playsLoop = false;
       objRef.animationSettings.plays = numTimes;
    }
  }

Notice that this script assumes the object will be traveling horizontally in a straight direction.

Run the script of your choice and use the EPUB Interactivity Preview panel to view the animation (Window > Interactive > EPUB Interactivity Preview).

ADD WHEELS

Of course, a wagon will not be much good without wheels, so this is the next step for your project. Create a new document similar to the one above. Add a circle with two lines criss-crossing in the center for the back wheel. Group it with its “spokes.” Copy the group to add a front wheel to the wagon. Name the front group “frontWheel” and the back one “backWheel.” Select all three items (wagonBase, frontWheel, backWheel) and group. Name this group “Wagon.” 

Your “Wagon” may look similar to the screen capture below:

screen capture of wagon group…Our simple wagon group

Your Layer structure should look like the following:

layer structure showing names for groups…Layer panel shows group structure

Change the name for the groupRef variable in the script above to “Wagon.”
AppleScript
   set groupRef to page item "Wagon" of spreadRef
JavaScript
   var groupRef = spreadRef.pageItems.itemByName("Wagon");

Run the script with this change. Clear the EPUB Interactiviy Preview window and click Play to make sure your wagon and wheels all move across the page together.

ROTATION

So far so good. But to be more realistic, we need to have the wheels rotate as the wagon moves. This gets a little tricky because each wheel is a group within a group. We can think of these as being child items within a parent group. You will make this work by modifying the script.

 

The script will look like the following. To test, make sure to add the toCurrentLocation handler (function) from above.

MyWagon (AppleScript)

set numTimes to 1 --number of times to animate
set dTravel to 1000 --distance to travel
set dTime to 3.0 --animation duration
set tOffsets to {1, 0.5} --object translation offset point
set rtime to 1.0 --duration for rotation
set rArray to {{0, 0.0}, {23, 720}}
set rOffsets to {0.5, 0.5}
set numRotates to 3
tell application "Adobe InDesign CC 2017"
	set spreadRef to spread 1 of document 1
	set groupRef to page item "Wagon" of spreadRef
	set wheel1Ref to page item "backWheel" of groupRef
	set wheel2Ref to page item "frontWheel" of groupRef
	repeat with eachItem in {wheel1Ref, wheel2Ref}
	   my setRotateProps(eachItem, rArray, rTime, numRotates, rOffsets)
	end repeat
    my toCurrentLocation(groupRef, dTime, dTravel, numTimes, tOffsets)
end tell
(*Rotates object given rotation array, duration, and repeat*)
on setRotateProps(objRef, rArray, dTime, numRotates, tOffsets)
   tell application "Adobe InDesign CC 2017"
	tell animation settings of objRef
	   set transform offsets to tOffsets
	   set duration to dTime
	   set rotation array to rArray
	   if numRotates < 0 then
	      set plays loop to true
	   else
	      set plays loop to false
	      set plays to numRotates
	   end if
	end tell
   end tell
end setRotateProps

MyWagon (JavaScript)

var numTimes = 1;
var dTravel = 1000;
var dTime = 3.0;
var tOffsets = [1, 0.5];
var rTime = 1;
var rArray = [[0, 0.0], [23, 720]];
var rOffsets = [0.5, 0.5];
var numRotates = 3;
var spreadRef = app.documents.item(0).spreads.item(0);
var groupRef = spreadRef.pageItems.itemByName("Wagon");
var wheel1Ref = groupRef.pageItems.itemByName("backWheel");
var wheel2Ref = groupRef.pageItems.itemByName("frontWheel");
setRotateProps(wheel1Ref, rArray, rTime, numRotates, rOffsets);
setRotateProps(wheel2Ref, rArray, rTime, numRotates, rOffsets);
toCurrentLocation (groupRef, dTime, dTravel, numTimes, tOffsets);

function setRotateProps (objRef, rArray, rTime, numRotates, rOffsets) {
   objRef.animatioonSettings.transformOffsets = rOffsets;
   objRef.animationSettings.duration = rTime;
   objRef.animationSettings.rotationArray = rArray;
   if (numRotates < 0) {
      objRef.anmimationSettings.playsLoop = true;
   } else {
      objRef.animationSettings.playsLoop = false;
      objRef.animationSettings.plays = numRotates;
   }
}

Timing Groups

If you test the script at this point you will see the wagon group move across the screen, then each wheel will rotate one after the other. This is default behavior: Animations proceed linearly, in order one after the other. What we want is for both wheels to rotate together as the wagon moves. For this, we need to create a timing group. Add the following to the top portion of your script.

For AppleScript this will be just above the end tell statement to the application:

tell timing settings of spreadRef
   delete timing lists
   set tList to make timing list with properties {trigger event: on page click}
   tell tList
      set g1 to make timing group with properties {dynamic target: groupRef, delay seconds: 0.0}
      tell g1
         repeat with eachItem in {wheel1Ref, wheel2Ref}
            make timing target with properties {dynamic target: eachItem, delay seconds: 0.0}
         end repeat
      end tell
  end tell --timing list
end tell --timing settings

For JavaScript this will be at the end of the top portion of the script

var tList = mySettings.timingLists.add({triggerEvent:DynamicTriggerEvents.ON_PAGE_CLICK});
var g1 = tList.timingGroups.add({dynamicTarget: groupRef, delaySeconds:0});
g1.timingTargets.add({dynamicTarget:wheel1Ref, delaySeconds:0});
g1.timingTargets.add({dynamicTarget:wheel2Ref, delaySeconds:0});

Notice that timing settings for the spread are used to trigger the animation when the page is clicked.

To see the final script in action, Click here

ON YOUR OWN

When working with timeline values, you will want to do some experimenting in setting up animations. Try changing the value of the numTimes variable to 3. Then change it to -1. What values will you need to use for the wheel rotation to make it consistent with these changes?

 

Hint: When numTimes is greater than 1 or equal to -1 (loop), you will want to change the rotation values to span the entire 3 second timeline.

set rTime to 3.0 --duration for rotation array
set rArray to {{0, 0.0}, {23, 360}, {47, 0}, {71, 360}} --rotation array

The value for number of rotations (numRotates) will be the same as that for numTimes. The settings for JavaScript will be similar.

UPWARD AND ONWARD

Should you want to have the animated object hidden when the page opens, add another property to the animation settings for the Wagon group:

AppleScript: set initially hidden to true

JavaScript: objRef.animationSettings.initiallyHidden = true;