Jump to content
GreenSock

santi

Change a text property at a specific time and reverse

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hi! 

 

I need to set a text property of a javascript object at a specific time on a timeline, and when reversing, the text should be reverted to its previous value.

 

Is there a simple way to accomplish this? I though delatedCall might help, but it seems I would need to handle the setting of the new/old values by hand checking if the timeline is reversed. Maybe a stepped easing?

 

I tried using to/fromTo animations to do so, but the text is prefixed with a 0/NaN, etc; I guess it's trying to animate it as if it where a number.

 

I was unable to find this question on the forums, but I apologize if it was asked before.

 

Great framework! Thanks in advance.

 

Link to comment
Share on other sites

You are correct, GSAP is for tweening numeric properties. It has a bunch of hidden smarts in things like CSSPlugin though to determine what the numbers are and how to set them, for things like { left:"20px" } or { boxShadow:"0px 0px 20px red" }.

It should be possible to write a GSAP plugin to handle a text change like this, although for cross browser compatibilty you're probably better just keeping it simple and going with a well tested, existing framework for working with text or html nodes. I've used something like this before and it should be workable:

myTimeline = new TimelineMax();
myTimeline.addCallback(changeText, 5, [$('#myTextElement'), "start", "end", myTimeline]);

function changeText(element, startText, endText, myTimeline) {
    if (myTimeline.reversed()) {
        element.text(startText);
    } else {
        element.text(endText);
    }
}

You'll just need to make sure to reverse() the timeline when going back to the start (yoyo doesn't affect the reversed property).

  • Like 1
Link to comment
Share on other sites

Hi Santi,

 

I interpreted your request a little differently than Jamie. His solution is really good but I interpreted your request a little differently.

 

 

You can addCallback functions in your time that will change the text properties of your object but when you play the timeline backwards there is no mechanism in place to remember what those text value were prior to each callback firing. Whatever callback function you might use to alter the text is sort of like a rogue external force modifying your object and the timeline doesn't really care what it does. Jamie's solution accounted for this by hard-coding "start and end" values for your Strings (very clever).

 

Also, as you noticed and Jamie suggested,  TweenLite can only tween numeric values, not String values. So if you want to tween text properties, one option is to have an object that has a tweenable numeric property that can be mapped to an element in an array of Strings.

 

You can than use TweenLite to set that numeric property to an exact value or even tween it!

 

Here I've created a timeline that uses both set() and to() methods to update the text that is displayed in a DOM element and it plays nicely forward and in reverse. 

 

 

 

var letter = $("#letterBox"),
    letterDisplay,
    tl;




letterDisplay = {
    letters: ["A", "B", "C", "D"],
    currentIndex: 0,
    currentLetter: function (index) {
        if (arguments.length > 0) {
            //set
            index = parseInt(index);
            letter.text(this.letters[index]);
            this.currentIndex = index;
        } else {
            //get
            return this.currentIndex;
        }
    }


};




  
var tl = new TimelineMax({repeat:3, yoyo:true});
tl.to(letter, 4, {left:400, ease:Linear.easeNone})
  .set(letterDisplay, {currentLetter:0}, 0)
  .set(letterDisplay, {currentLetter:1}, 1)
  .set(letterDisplay, {currentLetter:2}, 2)
  .set(letterDisplay, {currentLetter:3}, 3)
  .to(letter, 2, {top:200}, "down")
  .to(letterDisplay, 2, {currentLetter:0}, "down")
  
 tl.timeScale(1.5); 
 

 

 
live demo: 

See the Pen 3563e138b71347a5e5e53a886b021229 by GreenSock (@GreenSock) on CodePen

 
Again I understand you might not need something this elaborate but its a handy concept.
 
The reason it works is because TweenLite is configured to tween properties and also methods that act as getters and setters. In the case of currentLetter() if a parameter isn't passed in it gets / returns a value (which TweenLite records as the starting value) and when the tween is running the updated tweened value is passed into currentLetter() which then uses that value to pull out the right letter from the array and update the display.
 
Since its all happening with tweens in a timeline, all the starting and ending values are recorded and the whole sequence can be played in reverse very easily.
  • Like 1
Link to comment
Share on other sites

Thanks you both for the prompt reply! It's very good to have multiple alternatives :).

 

I was thinking in something like Jamie's, but I agree that mapping numbers to [] of values as a way to change them is quite flexible.

 

Tks!

Link to comment
Share on other sites

All good solutions, but I thought I'd throw one more out there: it'd be pretty easy to create a plugin for this sort of functionality. The plugin could record the original text and revert it if necessary. In fact, I just whipped together a plugin for you that does exactly that. See the attached file. 

 

Once you load the plugin, the code is pretty simple:

 

//we'll yoyo a TimelineMax so that you can see that things work backwards and forward
var tl = new TimelineMax({delay:1, repeat:-1, yoyo:true, repeatDelay:1});

//add the first set() call a little offset from the beginning so that when we yoyo and delay the repeat for a second, it shows the original text
tl.set("#content", {text:"First change of text."}, 0.001);
tl.set("#content", {text:"Second text change goes here."}, "+=1");
tl.set("#content", {text:"Final change of text here."}, "+=1"); 

As a little bonus, I made the plugin so that by default, it will toggle letter-by-letter, kinda like a typewriter. You won't see that in the example above because we're using set() which is just like a zero-duration tween, but feel free to experiment with doing to() tweens and you'll see. You can optionally set some variables too that will make the text go word-by-word instead of letter-by-letter. Wrap your stuff in an object ({}) and use the "delimiter" special property and set it to a space (" ") like:

 

TweenLite.to(element, 3, {text:{delimiter:" ", value:"This is the new text"}, ease:Linear.easeNone});

I hope this is helpful. 

TextPlugin_Example.zip

  • Like 4
Link to comment
Share on other sites

Amazing! More than what I expected :). Thanks!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×