Table of Contents

Scrolling (Ticker) text without masks

WatchMaker doesn't (yet) have a scrolling text function, so if you want to scroll text, you have to get creative. The most common way is to use a normal text object, and animate the “Position X” attribute. The problem with this is that you have to animate it such that it the start and end points have to be offscreen (or behind some higher-level mask). If only there were a way to scroll text without a mask… Well, there is. It has some caveats, but it's still a cool effect. Here's how.

Examples

On_millisecond method

Main Script

 window_length = 15
 text_sep = "               "
 startpos = 0
 endpos = 0
 text_work = ""
 var_slowdown = 300000
 var_ms_stringout = ""
 var_text = "Testing 1234567890"
 function on_millisecond()
     startpos = startpos + 1
     endpos = window_length + startpos
     text_work = var_text..text_sep..string.sub(var_text,1,window_length)
     pause = 0
     while pause <= var_slowdown do
         var_ms_stringout = string.sub(text_work,startpos, endpos)
         pause = pause + 1
     end
     if endpos == string.len(text_work) then
         startpos = 0
     end
 end

Text Field of Object(s)

 var_ms_stringout
   

Standard Function method

Main Script

 var_toggle=0
 var_text="Testing 1234567890"
 tweens.scroll=500
 var_speed=4
 function textscroll(tl)
    wm_schedule {action='tween',tween='scroll',from=0,to=tl,duration=var_speed,easing=linear}
 end
 function toggle()
    if var_toggle>0 then
      var_toggle =0
   else
     var_toggle =1
   end
 end

Text Field of Object(s)

tweens.scroll>=string.len(var_text)+16 and textscroll(string.len(var_text)+16) or string.sub("               "..var_text.."               ",tweens.scroll,tweens.scroll+15)

Explanation

Okay, notice that that two methods are listed. Remember, I mentioned some caveats earlier? Well, the truth is, there's no perfect way to create scrolling text, unless you're willing to limit yourself to a mono-spaced font (that is… a font where every character, including the letter i, m, or even a space, takes up the exact same amount of horizontal space). Most fonts use less space for a letter i than for a letter m, and a lot less space for an invisible space character. As is, WatchMaker isn't capable of making a “viewable area” window. If you want to limit viewable area, you do so by limiting the number of characters. Since a space, a letter i, or a letter m, is a character, but each takes up a different amount of horizontal line space, scrolling will look a little weird, because the letters won't always appear and disappear at the exact same spot. That's okay, though. The effect is still very useful, even without perfect alignment.

So… back to the two methods. Well, each has their pros and cons, and we'll explain them here, and it will be up to you to determine which method will work best in your particular use case.

The first method is the “on millisecond” method. This uses the “On_Millisecond” function in the main script. The main advantage to this method is that it's smoother, and the loop is seamless. That means that the beginning and end of the looped text can be visible at the same time. So, when the loop ends, it doesn't need to completely scroll out of sight before the next loop starts. However, this kind of loop is *constantly* running, so it's harder on your battery, and it tends to bog down the processor, even when the text isn't currently being displayed. It also tends to require more code than the standard function method, and the timing is a bit more reliant on the speed of your watch, so it's a bit harder to ensure a universal scrolling speed. Thus, the scrolling speed on your phone will tend to be *much* faster than on your watch, so be sure to test on both.

We start by defining some constants, such as the number of characters that will be shown at once (window_length), the scroll speed (var_slowdown), and a separator string. In the example, we use a series of spaces as the separator (between loops), but one advantage of this method is that you can use visible characters, such as dashes, underscores, or periods, as a separator as well.

Once we actually enter the function, we essentially move the visible part of the string along, limiting the visible portion to the window size. So, if we've determined the window size to be 15 characters, we'll show the 1st to 15th character, then the 2nd to 16th, 3rd to 17th, 4th to 18th, etc. If we run out of characters we simply use the “separator” string as a buffer, before starting over with the 1st character. Thus, it's perfectly acceptable to show the last 10 characters, followed by a 3-character separator, followed by the first 2 characters (to equal a 15-character window). Also, keep in mind that the example shows a variable set in the main script as the display text, but the string could just as easily be a tag such as {wct}.

The Text field, in this case, is very simple, because we did all of the processing in the main script. It is simply “var_ms_stringout”

The second method is a lot more battery and processor friendly, and the scroll speed is measured in seconds, making it consistent across devices, but the major disadvantage is that the text must completely scroll out of sight before it can start up again, because there is a slight delay as you recall the function (which restarts the scrolling text… as each function call only scrolls the text one time).

Here, we again start by defining some initial values for certain variables (mainly to prevent “null” errors), but in the case of “tweens.scroll,” we're going to “restart” it every time the value reaches the maximum value, so we need to initially set it to a value higher than it will ever be in normal use. Thus, it will immediately trigger our first function call by being higher than it should be. The speed control here is var_speed, and is in seconds (as in, how many seconds it will take to fully scroll the text).

The function, in this case is simply a “tween” animation, so it's easy to understand. Essentially, we do the same thing as in the “on_millisecond” method, but we use a standard function call to determine how long the display window should be, and we must recall that function every time we want to loop. This is best for screens that won't always be visible, such as weather screens that are called by tap action. Thus, the scrolling only happens when necessary, saving processor and battery.

The text object is a bit more complicated here, since we did very little processing in the main script. The important thing to remember here is that the text must scroll *completely* out of sight before restarting. We do this by padding the text with leading and trailing invisible spaces, equal to the window length. So, if we're showing 15 characters, then we must add 15 spaces before *and* after the text string. They must be spaces. You can't use visible characters with this method. Also, we must tell the function how many characters are to be displayed in the string, and finally, we must recall the function when the string is finished (and we've reached the end of the scroll). Performing three functions in a single “text field” may make for some confusing code, but your processor and battery will thank you.

You might notice that the string length is 15, but we tell it to scroll 16 characters in the tween statement. This is to ensure that it scrolls the last visible character completely out of sight, and ends by showing only spaces (no actual text). So, wherever you see 16 in the example, be sure to add 1 to the number of characters you want displayed. At the end, however, we do list the actual window length in the animation endpoint, so where you see 15 in the example, be sure to replace it with the actual number of characters to be displayed.

Let's be honest. If you were hoping for line-by-line explanation of the examples… well… that didn't happen. This is not a beginner's paradise. On a scale of 1 to 10, scrolling text is easily in the 9 category, at the very least. This is why you haven't seen a whole lot of it up to now. The explanation assumes some coding knowledge, and while the examples are complete, they are intended for experienced coders. I'm sure that some world-class instructor could help make this easier to understand, but unfortunately, that's not me.

I offered this as a coding challenge, and originally, I simply had fixed text, and scrolled the X coordinates. Willum Kerker blew my mind with his (on_millisecond) solution. I adapted it for my use (Standard Function method), but even so, it's his method, and while I can understand how he pulled it off, understanding and explaining are two separate things. In fact, if you really want your mind blown, take a look at his actual submission, which includes variable speed (and multiple tag) scrolling: https://www.dropbox.com/s/y39gsjs70d3sfwe/ticker-contest.watch?dl=0

Amazing, no?