Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
Exhumator

Randomly changing text in DIV via TextPlugin

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

Greetings!

 

I am trying to randomly change text in DIV in the timeline with "text" attribute (TextPlugins is loaded) but it doesn't work. I think I miss something important but don't know what it is.

 

The right scenario of this codepen would be:

  1. Randomly set value from "messages" array.
  2. Change color to red.
  3. Repeat it.

 

Could anybody give me advice how to do it, please? :)

See the Pen VJQbMZ by MannySVK (@MannySVK) on CodePen

Link to comment
Share on other sites

Hi, @mikel :) Thanks for your effort and code. It works good. But i still don't understand why do I have to do it this way? Why my code doesn't work?

Link to comment
Share on other sites

I've seen modifiers plugin, why this doesn't work either? I thought modifiers plugin is made for this.

 

var messages = ["1", "2", "3", "4", "5"];

var tl = new TimelineMax({
	repeat: -1
});

function getRandomValueFromArray(a) { return a[Math.floor( Math.random() * a.length )]; }

tl.set("#message", { text: "this works well" });
tl.set("#message", { 
	modifiers: {
		text: function() { return getRandomValueFromArray(messages); }
	}
});
tl.to("#message", 1, { color: "red" });

 

Link to comment
Share on other sites

Let's break down what your code is doing:

 

// Setting the element's text to this string (at the beginning)
tl.set("#message", { text: "this works well" });

// Setting the element's text to a random value in the array (at the beginning)
tl.set("#message", { text: function() { return getRandomValueFromArray(messages); } });

// Animating the message's color to red
tl.to("#message", 1, { color: "red" });

 

GSAP assumes that only the animations should be repeated when the timeline is replayed, not the .set() calls and and animations. 

 

In order to have it do both, you should put the set call inside of the onRepeat callback. You also need to set the position in the timeline of it to 0, but I'm not quite sure why you need to do that (maybe @GreenSock or another mod can help me out with understanding why). The code would then look like this:

 

var messages = ["1", "2", "3", "4", "5"];

var tl = new TimelineMax({
	repeat: -1,
	onRepeat: function() {
		tl.set("#message", { text: function() { return getRandomValueFromArray(messages); } }, 0);
	}
});

function getRandomValueFromArray(a) {
  return a[Math.floor( Math.random() * a.length )];
}

tl.set("#message", { text: "this works well" });
tl.to("#message", 1, { color: "red" });

 

See the Pen NZyvLG?editors=0010 by ZachSaucier (@ZachSaucier) on CodePen

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

As for your modifiers approach, I am not sure if modifiers work with the text attribute. I do know that the modifier should be on the .to, not the .set call though.

 

It's possible my approach is wrong. Maybe @GreenSock or another mod can help here as well.

  • Thanks 1
Link to comment
Share on other sites

2 hours ago, ZachSaucier said:

You also need to set the position in the timeline of it to 0, but I'm not quite sure why you need to do that

 

That is necessary because you're adding that set() to the existing timeline. If you added it without the position parameter of 0, it would simply get added to the end of the timeline. All the sets that you're adding wouldn't really appear to fire because the timeline starts over and the first message set() of "this works well" would appear instantly. 

 

You can check the children on each iteration:

console.log(tl.getChildren().length);

 

I'm not sure using a timeline here has any real advantage and you're adding children with each repeat. If it were me, I'd probably just put this in a function that calls itself when the color tween completes.

 

Maybe something like this:

See the Pen YoeEWp by PointC (@PointC) on CodePen

 

Happy tweening.

:)

 

Edit: Whoops — looks like @mikel did the same thing, but I hadn't looked at his demo yet. 

 

 

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

14 hours ago, ZachSaucier said:

GSAP assumes that only the animations should be repeated when the timeline is replayed, not the .set() calls and and animations. 

 

Just to clarify, this isn't the case. A set() call is just a zero-duration tween. When the playhead travels past that point (in either direction), it will trigger it accordingly. 

 

The main point of confusion here (I think) is a misunderstanding about what repeating actually means and the work GSAP does. When a tween renders for the first time, it records the starting and ending values internally so that it can very quickly interpolate between them on the fly on each tick. If you rewind the playhead and play that tween again, it doesn't go back out and try to read the then-current values again to re-record things internally. That's typically very wasteful. It sounds like you were expecting it to keep calling that function to get new values. But that wouldn't be a true "repeat", as things would change :)

 

You can tell a tween to forget its recorded values and have it re-initialize the next time it renders by calling invalidate() on it. Same for entire timelines. 

 

So you could accomplish what you're after by removing the repeat logic completely from your initial demo, and just use an onComplete: 

 

var tl = new TimelineMax({
    onComplete: function() {
        this.restart().invalidate(); //restarts and forces it to re-record starting/ending values
    }
});

 

Does that help? 

 

I like the suggestions @PointC and @mikel made as well. 

 

Oh, and the modifiers thing wouldn't be good for this because a modifier literally gets called on EVERY render. So your example would have various values constantly changing randomly in the text (about 60 times per second). 

 

Let me know if any of this doesn't make sense. 

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

@GreenSock thanks for clarification. Now i understand i need to use timeline.invalidate() method when i want to change some of the cached values, like inner html. 

  • Like 1
Link to comment
Share on other sites

On 7/1/2019 at 5:48 AM, GreenSock said:

A set() call is just a zero-duration tween.

So, are these codes equal?

 

Code #1:

tl.set("element", { color: "red" }); // code #1
tl.to("element", 0, { color: "red" }); // code #2

 

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.
×