MOTION PATHS

When it comes to writing scripts to create animations in InDesign, defining the motion path for your object may become your number one headache.

STRAIGHT PATHS

To set up a path for animating a page object to travel in a straight line is not as simple as it sounds:

  • Define the x- and y-coordinates for the begin and end point.
  • Then add a boolean to indicate if the path is open (true) or closed (false).

The problem here is that each point in the path is a list of three points: the anchor, the left direction control, and right direction control. The array (list) to describe this gets a little scary when there are a number of points to define.

When a point does not define a curve, all three coordinate pairs for the point are the same. Try the following script with a single page document in InDesign open. Run the script and view the result in EPUB Interactivity Preview panel (Window > Interactive > EPUB Interactivity Preview).

Path Points – AppleScript

set gBounds to {90, 0, 110, 100}
set pathPoints to {{{{0, 200}, {0, 200}, {0, 200}}, {{500, 200}, {500, 200}, {500, 200}}}, true}
set numberSeconds to 2

   tell application "Adobe InDesign CC 2017"
	set measurement unit of script preferences to pixels
	set ruler origin of view preferences of document 1 to page origin
	set spreadRef to active spread of active window
	set objStyle to object style 1 of document 1
	set rectRef to my makeDefaultRectangle(spreadRef, gBounds, objStyle)
	tell animation settings of rectRef
		set design option to from current appearance
		set duration to numberSeconds
		set transform offsets to {1, 0}
		set motion path points to pathPoints
		set plays to 1
	end tell
   end tell


   on makeDefaultRectangle(spreadRef, gBounds, objStyle)
	tell application "Adobe InDesign CC 2017"
	   tell spreadRef
		set myRectangle to make rectangle with properties {geometric bounds:gBounds, object style:objStyle}
	   end tell
	end tell
   end makeDefaultRectangle 

Path Points – Extend Script

   var gBounds = [90,0, 110, 100];
   var pathPoints = [[[[0, 200], [0, 200], [0, 200]], [[500, 200], [500, 200], [500, 200]]], true];
   var numberSeconds = 2;

   app.scriptPreferences.measurementUnit = MeasurementUnits.PIXELS;
   var docRef = app.documents.item(0);
   docRef.viewPreferences.rulerOrigin = RulerOrigin.PAGE_ORIGIN;
   var spreadRef = docRef.spreads.item(0);
   var objStyle = docRef.objectStyles.item(0);
   var rectRef = makeDefaultRectangle(spreadRef, gBounds, objStyle);
   rectRef.animationSettings.duration = numberSeconds;
   rectRef.animationSettings.designOption = DesignOptions.FROM_CURRENT_APPEARANCE;
   rectRef.animationSettings.motionPathPoints = pathPoints;
   rectRef.animationSettings.transformOffsets = [1, 0];
   rectRef.animationSettings.plays = 1;


   function makeDefaultRectangle(spreadRef, gBounds, objStyle) {
    var myRectangle = spreadRef.rectangles.add({geometricBounds:gBounds, ObjectStyle:objStyle});
	return myRectangle;
   }

DIRECTION CONTROLS

Change just one coordinate for a direction control, and suddenly your path becomes a curve. Change the list for the pathPoints variable above to read as follows and test. 

AppleScript

set pathPoints to {{{{0, 200}, {0, 200}, {0, 200}}, {{500, 200}, {500, 50}, {500, 200}}}, true}

ExtendScript

   var pathPoints = [[[[0, 200], [0, 200], [0, 200]], [[500, 200], [500, 50], [500, 200]]], true];

ADDING POINTS

Try adding a point in the center of the path and experiment with setting the left and right curve controls:

AppleScript

   set pathPoints to {{{{0, 200}, {0, 200}, {0, 200}}, {{250,200}, {250, 50}, {250, 350}}, {{500, 200}, {500, 200}, {500, 200}}}, true}

Extendscript

   var pathPoints = [[[[0, 200], [0, 200], [0, 200]], [[250,200], [250, 50], [250, 350]], [[500, 200], [500, 200], [500, 200]]], true]

ADDING TIMING (KEYFRAMES)

Adding timing values (keyframes) to the motion path definition increases the difficulty in writing the Motion Path array. But it is not that hard if you break the process down:

  • Add a curly brace, the keyframe number, and a comma in front of each point set (three coordinate pairs) for the path
  • Add a single curly brace after each point set

Illustration showing motion path points array structure…adding keyframes to motion path

set pathPoints to {{0, [{0, 200}, {0, 200}, {0, 200}}], {23, {{250,200}, {250, 50}, {250, 350}}}, {47, {{500, 200}, {500, 200}, {500, 200}}}}

Notice that the pathPoints array above no longer has the true (path open boolean) at the end. When working with keyframes you use the motion path property instead of the motion path points property for animation settings.

The AppleScript dictionary makes this very clear. (The animation settings property is found in the preferences suite.)

   motion path (list of any): The list of motion path points and key frames for this animation…

The motion path points property does not include key frames but does require the path open boolean:

   motion path points (any): The list of motion path points for this animation…path open:boolean

Also make sure to change the duration (numberSeconds variable) to accommodate the number of keyframes. For instance: for an animation having three keyframes of 1 second each, you will need to increase the value for numberSeconds (duration) to 3.

   set numberSeconds to 3 
   ...
tell animation settings of rectRef
   set design option to from current appearance
   set duration to numberSeconds
   set transform offsets to {0.5, 0.5}
   set motion path to pathPoints
   set plays to 1
end tell

PLOTTING THE MOTION PATH

Now that you have the basics for creating the Motion Path array, the next problem is how to determine the values for each point. Plotting paths with non-curve points is fairly simple, especially if you can calculate the points mathematically. But mathematics can turn into a brain teaser especially if curves are involved. Let InDesign do the work for you.

Pen Tool to the Rescue

Start with a document the same size as your completed animation.
Create your animation object at its starting position on the page. Hint: use your script with the animation settings commented out:

   set gBounds to {90, 0, 110, 100}

   tell application "Adobe InDesign CC 2017"
	set measurement unit of script preferences to pixels
	set ruler origin of view preferences of document 1 to page origin
	set spreadRef to active spread of active window
	set objStyle to object style 1 of document 1
	set rectRef to my makeDefaultRectangle(spreadRef, gBounds, objStyle)
	--comment out animation settings
	(*tell animation settings of rectRef
		set design option to from current appearance
		set duration to numberSeconds
		set transform offsets to {1, 0}
		set motion path points to pathPoints
		set plays to 1
	end tell*)
   end tell 
   --add makeDefaultRectangle handler here
  • Change the swatches panel to None fill and a colored stroke.
  • Pick up the pen tool and use it to create the motion path.
  • For an animation that will progress from left to right the first point for the path will be the transform offsets location for the animated object.
  • With the page item at its desired beginning point, use the pen tool to touch the page on the page item’s transform offsets location
  • Touch the page with the pen tool at each of the desired path points
    (Don’t drag the pen at points unless you want Bezier curves.)
  • With the path drawn and selected, change to the selection tool. Hold the shift key down and select the page item to be animated.
  • In InDesign’s Object menu, click on Interactive and select Convert to Motion Path from the flyout menu.
    Convert to Motion Path is also available from the Animation panel’s contextual menu (Window > Interactive > Animation opens the panel.)

With the path and the page item selected, run the following script:

getPathPoints Script

AppleScript

   tell application "Adobe InDesign CC 2017"
	set selList to selection
	set selItem to item 1 of selList
	tell animation settings of selItem
		set thePath to motion path points
	end tell
   end tell
   thePath

ExtendScript

   var selList = app.selection;
   var selItem = selList[0];
   var thePath = selItem.animationSettings.motionPathPoints;
   thePath

Copy the Result from running the script. For the pathPoints variable at the top of the script, paste in the result. Change the value of the numberSeconds variable to correspond with the number of points in the path. Uncomment the animation settings portion of the script. The script for an arbitrary path of five non-curve points without keyframes will read similar to the following:

   set gBounds to {90, 0, 110, 100}
   set pathPoints to {{{{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}, {{161.0, -65.0}, {161.0, -65.0}, {161.0, -65.0}},¬ 
   {{286.0, 101.0}, {286.0, 101.0}, {286.0, 101.0}}, {{425.0, 21.0}, {425.0, 21.0}, {425.0, 21.0}},¬
   {{678.0, 194.0}, {678.0, 194.0}, {678.0, 194.0}}}, true}   
   set numberSeconds to 5
   tell application "Adobe InDesign CC 2017"
	set measurement unit of script preferences to pixels
	set ruler origin of view preferences of document 1 to page origin
	set spreadRef to active spread of active window
	set objStyle to object style "[Basic Graphics Frame]" of document 1
	set rectRef to my makeDefaultRectangle(spreadRef, gBounds, objStyle)
	tell animation settings of rectRef
		set design option to from current appearance
		set duration to numberSeconds
		set transform offsets to {1, 0}
		set motion path points to pathPoints
		set plays to 1
	end tell
   end tell
   --add makeDefaultRectangle handler here

Delete the path and animated page item from the page and run your script with the motion path points from the getPathPoints script added.

ADD TIMING

Convert to Motion Path does not take timing keyframes into consideration. To add keyframes the frame value is added to each point in the motion path as needed. (See discussion above.) The pathPoints variable above will now read as follows:

   set mpath to {{0, {{0, 0}, {0, 0}, {0, 0}}}, {23, {{200, 0}, {200, 0}, {200, 0}}}, ¬
   {47, {{200, 200}, {200, 200}, {200, 200}}}, {119, {{0, 200}, {0, 200}, {0, 200}}}, {143, {{0, 0}, {0, 0}, {0, 0}}}}

Notice that the open path boolean (true) is removed as we will be using the motion path property instead of motion path points.

   tell animation settings of rectRef
     set design option to from current appearance
     set duration to numberSeconds
     set transform offsets to {.5, .5}
     set motion path to mPath
     set plays to 1
   end tell

Remove the original animation from the page and run the script that now has keyframes added. Preview the animation in the EPUB Interactivity Preview panel.

ADD ROTATION

Now that you have added keyframes, wouldn’t it be interesting to rotate the page item as its angle of direction changes. Adding rotation (rotation array) is easy, but figuring out what the angle settings need to be is another matter. Again, let InDesign do the work for you. Click on the animated page item to reveal the motion path. Use the ruler tool to draw a line over the path segment.

demonstrates using ruler tool to determine path angle…Using ruler tool to determine path angle

Now open the info panel (Window > Info) and read the angle setting there. The only problem is that you need to reverse the positive/negative signs for the angle reported. So if the angle reads 22, use -22. With this adjustment our rotation array values were set as follows (yours will be different):

set rotArray to {{0,0}, {23, -22}, {47, 53}, {71, -29.4}, {95, 34.3}}

Add the rotation array to the animation settings for the animated page item:

  tell animation settings of rectRef
	set design option to from current appearance
	set duration to numberSeconds
	set transform offsets to {0.5, 0.5}
	set motion path to mPath
	set rotation array to rotArray
	set plays to 1
  end tell

Remove the previous animation from the page, and run the script with rotation values added. View the animation in the EPUB Interactivity Preview panel.

The problem is that the rotation angle for the animated page item changes gradually between points. You may wish to change the angle sooner and have the angle maintained until the next point is reached. You are not limited to setting rotation values at the same keyframes as the motion path. For the purpose of demonstration, we added a keyframe midway between the motion path points to force the rotation to occur earlier and then keep the same rotation at the next motion path point:

   set rotArray to {{0, 0}, {11, -22}, {23, -22}, {36, 53}, {47, 53}, {60, -29.4},¬
    {71, -29.4}, {84, 34.3}, {95, 34.3}}

Do some experimenting with your animation: change the path, change the rotation array, change the keyframe values. Have fun with it.

ONWARD AND UPWARD

Now that you are familiar with motion path points and motion path, try creating a path that includes curves. Use the same procedure as above taking advantage of InDesign’s ability to convert two selected objects to a motion path and have it calculate the path for you.