TEXT ON A PATH

Taking a short detour from automating animations in InDesign to look at a subject that came up recently in the user forums: text on a path. In working with text on a path you may have come across some issues that were a little difficult. That’s probably the reason that there are so many YouTube videos “out there” focusing on the subject. So why write a script? If you find yourself creating badges or other circular logos that require text on a path, you may find the following discussion most beneficial. And, because we will discuss the creation of a script step by step, you may find some code that can be reused for other purposes.

THE SCRIPT: TEXTONAPATH

The script will assume that the user has a document open with a circle (oval) selected. The first step of the script will place a reference to the oval selected into a variable selItem:

Step 1

Inside a tell statement block to the application, get a selection and make sure it is an oval. Selection returns a list of items. To make sure an object is selected we test to see if the value returned is an empty list (no object is selected). Next, the script checks the class of the first item of the list. If selection is empty or the class of the first item in the script is not oval, the script needs to give the user a message and exit from the script. Since this functionality is something that could be used many times in other scripts, we will set this up as a handler (known also as a subroutine, or function). The try statement block will give the user a message and exit from the script if an error is encountered in the handler.

tell application "Adobe InDesign CC 2017"
   try
      set selItem to my getSelection (oval)
   on error errMsg
      display alert errMsg
      return
   end try
end tell
(*The handler. tests for selection and class. Throws error if no selection exists or first item of selection is mot of type passed to handler as its only argument *)
on getSelection(classType)
   tell application "Adobe InDesign CC 2017"
      set selList to selection
      if length of selList > 0 and class of item 1 of selList is classType then
	 return item 1 of selList
      else
	 error "Requires oval selection"
      end if
   end tell
end getSelection

Test It
Copy the above code to the script editor for AppleScript. With an InDesign document open and a circle selected, run the script. Next, run the script with nothing selected and then with an object other than a circle (oval) selected.

Not using version CC 2017 for InDesign? Change the designation for the application in the above accordingly.

Step 2

Define the text that will be placed on the text path. For now, you can just define it at the top of the script.

set textStr to "This is text on a path"

Step 3

Define a paragraph style that will be used to style the text once it is placed on the text path. Here, again is functionality that could be used in any number of scripts. We will create another handler just for this purpose. It will test to see if a paragraph style as named in the handler’s argument list exists. If not a paragraph style will be created. For our purpose, only the name, font size, and justification will be defined for the style. All other properties will be inherited from the document’s text defaults. We can place the call to the handler just before the end tell statement in the top portion of the script above.

set styleProps to {point size: 24, justification: center align}
set parastyleRef to my makeParagraphStyle (document 1, "pathStyle", styleProps)

Test It
Add the call to the handler to the top portion of the script above (just before the on error statement.

Step 4

Add the following handler to the bottom of the script.

(*Checks if paragraph style as named in argument list exists. If not, a paragraph style is created with the name, point size, and justification; otherwise, reference to existing style is returned*) 
on makeParagraphStyle (docRef, styleName, styleProps)
   tell application "Adobe InDesign CC 2017" 	
      tell docRef		
         if not (exists paragraph style styleName) then 		 
            set parastyleRef to make paragraph style with properties {name:styleName} & styleProps
         else 		 
            set parastyleRef to paragraph style styleName 		
         end if 	
      end tell 
   end tell 
   return parastyleRef
end makeParagraphStyle

Step 5

With the above in place and working, we are now ready to create the text path and set its styling. Immediately after the end try statement in the above, add the following:

   tell selItem
      set textPathRef to make text path
   end tell
   tell textPathRef
      set contents to textStr
      set path effect to rainbow path effect
      set path alignment to top path alignment
      set text alignment to center text alignment
      set flip path effect to not flipped
      tell paragraph 1 of parent story to apply paragraph style using parastyleRef
   end tell

Test It
Compile the script (hammer button). Select a circle in the active document and run the script (Command+R). If all goes right, your text path should look similar to the screen capture below.

Text placed on top of circular text pathj…Text placed on text path

EXPLORE TEXT PATH SETTINGS

You may want to open InDesign’s AppleScript scripting dictionary to view the properties and settings that can be used with a text path. (With Script Editor active, select Open Dictionary… from the File menu. Select the version of InDesign you are using from the list presented.) You will find the entry for Text Path in the Text suite. 

Entry for text path in AppleScript Dictionary…Text path entry in dictionary

Depending on the version of InDesign you are using, you may want to do some experimenting to make sure some of the properties listed actually work. For instance, path alignment has the following options: top path alignment, bottom path alignment, center path alignment. With this, one would assume changing path alignment to bottom path alignment in the script above would cause the text to align at the bottom of the circle. This may or may not work. What does work in CC 2017 is start bracket and end bracket.

Text Path Brackets

The text path brackets start bracket and end bracket indicate the portion of the path that will be used for the text. The real value (number with decimals) used for this setting is based on the circumference of the circle (length of the path). This starts with 0 at bottom center and increases in value counter-clockwise. Fortunately for us, measurement units are in points and InDesign calculates the start bracket and end bracket for us. We can use the start bracket from the script above to calculate brackets to be used for text on the path bottom.

Text at Path Bottom

Change the text inside the tell textPathRef block above to read:

tell textPathRef
   set contents to textStr
   set path effect to rainbow path effect
   set path alignment to bottom path alignment
   set text alignment to center text alignment
   set flip path effect to flipped
   tell paragraph 1 of parent story to apply paragraph style using parastyleRef
   set a to start bracket
   set end bracket to a/4
   set start bracket to (a/4)*3
end tell

Test It
Compose the script and correct any typing errors. Select another circle on the page and run the script with the changes. The path should look similar to the screen capture below.

Text on bottom of circular path…Text placed on bottom of path

ONE SCRIPT TWO OPTIONS

Now that you are successful in creating text at the top and bottom of a text path, let’s modify the script so that one script can offer both options. We can do this by moving the styling for the text path to a handler and defining the text for the paths in a list. For now, the list will allow two items (1) text for the top of the path; (2) text for the bottom of the path. Change the textStr variable at the top of the script to read:

set textList to {"Text for top of text path", ""}

To create the handler, at the bottom of your script start with on and end statements:

on stylePath (textPathRef, textItem, textIndex, parastyleRef)
   tell application "Adobe InDesign CC 2017"
      --place code here
   end tell
end stylePath

Cut all of the code from tell textPathRef block in the script above (Command+X) and paste it (Command+V) inside the on/end statements you just added. Change the code inside the tell block so the handler reads as follows:

on stylePath(textPathRef, textItem, textIndex, parastyleRef)
   tell application "Adobe InDesign CC 2017"
	tell textPathRef
	   set path effect to rainbow path effect
	   set text alignment to center text alignment
	   set contents to textItem
	   tell paragraph 1 of parent story to apply paragraph style using parastyleRef
           --for bottom
	   if textIndex = 2 then
		set a to start bracket
		set flip path effect to flipped
		set end bracket to a / 4
		set start bracket to (a / 4) * 3
	   else
		--for top
		set flip path effect to not flipped
	   end if
	end tell
   end tell
end stylePath

All you need now is the call to the handler. We can place the call just before the last tell statement in the top portion of the script. The top portion should now read as follows:

TextOnAPath

set textList to {"Text for top of text path", ""}
tell application "Adobe InDesign CC 2017"
   try
      set selItem to my getSelection(oval)
      set styleProps to {point size:24, justification:center align}
      set parastyleRef to my makeParagraphStyle(document 1, "pathStyle", styleProps)
   on error errMsg
      display alert errMsg
      return
   end try
   tell selItem
      set textPathRef to make text path
   end tell
   my stylePath(textPathRef, item 1 of textList, 1, parastyleRef)
end tell

If you start a new script with this for the top portion, don’t forget to include the following handlers: makeParagraphStyle, stylePath, and getSelection

Test It
When you run the script with a circle selected, your text should be placed on the top of the path. Note that you cannot use the same circle to create text for the bottom of the path simply because a single page item can only have one text path. But you can use another circle. Change the textList at the top of the script to read:

set textList to {"","text for bottom of text path"}

Change the call to the handler to read:

my stylePath(textPathRef, item 2 of textList, 2, parastyleRef)

Test It
Run the script again, with another circle selected.

CREATING A BADGE

For a badge (having both top and bottom text on s path) you could create two circles and physically move the two on top of one another. Or, you could make a few changes to the script to duplicate the first circle for a second text path. Let’s see how this latter option would work.

Right after the end try statement, have the script test to see if the second item in the textList is not empty. If not, the first circle is duplicated and the text path for the bottom text is created. The script assumes that the top portion of the path will have text. Replace the four lines of code after the end try statement (up to end tell), and replace with the following:

if item 2 of textList is not "" then
   set dupItem to duplicate selItem
   tell dupItem
      set pathList to text paths
      if pathList is {} then
      set dupPathRef to make text path
     else
       set dupPathRef to text path 1
     end if
   end tell
   my stylePath(dupPathRef, item 2 of textList, 2, parastyleRef)
end if
tell selItem
   set pathList to text paths
   if pathList is {} then
     set textPathRef to make text path
   else
     set textPathRef to item 1 of pathList
   end if
end tell
my stylePath(textPathRef, item 1 of textList, 1, parastyleRef)

Finally, change the list at the top of the script to read:

set textList to {"Text for top of text path", "Text for bottom of text path"}

Select a new circle and run the script. When it completes successfully, congratulate yourself for a job well done.

…Badge created with script

ONWARD AND UPWARD

Add more property definitions for the paragraph style created. Perhaps you may add user-defined choices for color fill and/or stroke. Change the settings for the text path so the text aligns on the inside of the circle. Try other text path options.

To make the script user-friendly, you will want to add a custom user dialog for entering text for top and bottom of the text path. Perhaps, the dialog can also allow the user to choose a paragraph style and color swatch from two drop downs. We will show you how to create the user dialog for your TextOnAPath script in our next blog post.

Disclaimer: Scripts are presented for demonstration only. No representation as to completeness or accuracy is implied. Use at your own risk.