Jump to content
Search Community

TextPlugin speed calculation?

katerlouis test
Moderator Tag

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

I was implementing my own typewriter-effect when I stumbled upon the TextPlugin.

And I love it!

 

Since it is used as a simple property in the vars-object you still have to set your own timing of the tween.

But I will mostly need a kind of "characters per second" speed, therefore the duration is not always the same.

I don't want to calculate that again and again everytime I use it.

 

How would you approach this?

My idea is to enhance GSAP with TimelineMax.prototype.typewriter( elem, charsPerSec, delimeter )

But before I go down that road I'd rather ask if this is a good idea :o

 

 

Thanks!

Link to comment
Share on other sites

15 hours ago, kreativzirkel said:

My idea is to enhance GSAP with TimelineMax.prototype.typewriter( elem, charsPerSec, delimeter )

But before I go down that road I'd rather ask if this is a good idea :o

 

What is this prototype you speak of? I can't find it anywhere in the docs. :P

 

Now you're being proactive! If something is missing or can be improved in GSAP, just add it to the prototype. That's what makes jQuery so flexible. All plugins hook into its prototype using $.fn., and can then be used everywhere.

 

$.fn.style = function(vars) {
  TweenLite.set(this, vars);
  return this;
};

// Select and set at same time
var boxes = $(".box").style({ x: 100, y: 100, rotation: 90 });

 

 

So yeah, I think it's a good idea. Strings have a length property, so it will be real easy to calculate the speed. If you're using a delimeter, you could use .split() and get the length property from the array it creates.

 

var duration1 = text.length / charsPerSecond;
var duration2 = text.split(delimiter).length / wordsPerSecond;

 

Simple demo seeing how the TextPlugin works with emojis. Uggghhh... I was really hoping for an emoji typewriter, but that might have to wait. On my computer, the chars animation displays a question mark icon before rendering the emoji. @GreenSock may want to look into that. We had a similar problem with the SplitTextPlugin.  

 

 

  • Like 2
Link to comment
Share on other sites

Kind of off topic, but you brought up the prototype, and I wanted to show you something that you will probably like. I really liked your idea in this thread about using false or "none" for a linear ease because it is annoying having to specify that considering the engine is already doing that. And around that time, somebody asked about having a default ease for a timeline in this thread, which I thought was a good idea. So I wanted to see how hard it would be to implement both of those features.

 

I took me about 5 minutes to get it working. All I had to do was override/intercept the animation methods on the timeline prototype, and inject an ease into the tween before gsap gets a hold of it. That might sound complicated, but it's really easy to do.

 

For reference, the vars object you pass into a tween, timeline, draggable, etc, gets added to the instance itself, so you can always access it whenever you want. And as long as it is not a reserved keyword that GSAP uses, you can add whatever you want to it. So adding a default ease to a timeline is just a matter of passing one in.

 

var tl = new TimelineMax({ defaultEase: "foo" })

console.log(tl.vars.defaultEase); // => "foo"

 

Now we need to inject that ease into any animations that don't have an ease defined. To do this, we can override a timeline method with our own. We of course don't want to override everything, so we'll save the original method in a variable.

 

// Save original method
var originalTo = TimelineLite.prototype.to;

// Now override it with our own method, and call the original inside of it
TimelineLite.prototype.to = function(target, duration, vars, position) {  
  
  // Now we can do stuff before the original method gets called
  // I'm in your base, killing your d00ds
  
  return originalTo.call(this, target, duration, vars, position);
};

 

Now we need to check if there is an ease on the vars object being passed in. If there is an ease on the object that is equal to false or "none", we will a add linear ease to the vars object. If there isn't an ease on the vars object and the timeline has a default ease, we will add the default ease to the vars object.

 

TimelineLite.prototype.to = function(target, duration, vars, position) {  
  
  var currentEase = vars.ease;
  var defaultEase = this.vars.defaultEase;
  
  if (currentEase === false || currentEase === "none") {
    vars.ease = Linear.easeNone;
  } else if (!currentEase && defaultEase) {
    vars.ease = defaultEase;
  }  
  
  return originalTo.call(this, target, duration, vars, position);
};

 

 

And that's it! You just unlocked the Prototype Overrider achievement and gained 500XP. 

 

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

 

  • Like 4
Link to comment
Share on other sites

Clever approach for sure. Prototype overrider achievement earned ;)

 

However, we don't generally encourage this type of thing because it can lead to confusion. It introduces non-standard behavior and it may not be obvious to others who read your code later and don't know that you messed with the prototype to get certain functionality. In other words, they might see tweens with ease:false or a TimelineLite with a vars object containing a defaultEase and they try to do the same thing in their code using the official GSAP and it doesn't work and they get frustrated or they can't find it in the docs. 

 

Of course it's totally up to you, and if you want to implement this approach in your project it may work great especially if you're the only person who will ever work on it. 

 

I usually prefer to just write my own wrapper/helper functions to get the kind of functionality I need. To each their own, though. Blake has mad skills, so I put a lot of stock in his recommendations. 

 

As for the emoji stuff, I'll look into that. It's related to the fact that emoji characters actually consist of TWO characters (or sometimes even four). 

  • Like 2
Link to comment
Share on other sites

I like Jonathans typewriter "hack" ;) – No need for TextPlugin or SplitTextPlugin

Worth noting, though: playing with the width like that only works with mono-spaced fonts. 

 

Really love Blakes contributions here.

But I see why a GSAP parent wants to protect conformity in community talk.

Plus: I fear you need Blakes mad-skillz to enhance existing gsap functions – If you don't know what you're doing there, things may break, right?

Not so much if you enhance TweenMax with new functions (hoping the namespace won't collide with future versions)

 

Jake, what exactly do you mean by helper functions in this context? Could you provide an example by showing how you would solve the thread-issue of CharsPerSec with one of these helper functions?

 

PS: Sweeeet forum improvements 8)

  • Like 1
Link to comment
Share on other sites

On 5/12/2017 at 7:08 AM, kreativzirkel said:

Really love Blakes contributions here.

But I see why a GSAP parent wants to protect conformity in community talk.

Plus: I fear you need Blakes mad-skillz to enhance existing gsap functions – If you don't know what you're doing there, things may break, right?

Not so much if you enhance TweenMax with new functions (hoping the namespace won't collide with future versions)

 

It's not all about having mad-skillz. In general, it's not a good idea to modify objects you don't own. But the biggest reason for not doing this is what Jack said, it may create confusion for anybody reading your code. Even if you're the only person doing the coding right now, somebody may have to rework your code in the future, like with a site redesign.

 

So the safest way to customize a timeline would be to create a wrapper object, much like jQuery does with elements, but that requires you to reimplement a lot of stuff. Another option would be to create a subclass of a timeline. This is pretty easy to do using the new class syntax and super keyword. There is still a risk of a name collision, but using the super keyword eliminates the need to modify the original Timeline object.

 

See the Pen 997615151d42cbd55b1255ade15366a1 by osublake (@osublake) on CodePen

 

 

 

 

 

  • Like 1
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.
×
×
  • Create New...