Jump to content
GreenSock

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

How to work with new labels object in GSAP 3

Recommended Posts

With prior versions of GSAP, TimelineMax had a getLabelsArray() method which returned and array making it very easy to dynamically loop through the array of label objects and do stuff like create nav buttons for each label.

 GSAP code below shows how I would commonly work with the labels array:

 

let tl = new TimelineMax()
.add("milk", 1)
.add("cookies", 2)
.add("beans", 3)
.add("rice", 4)

let labels = tl.getLabelsArray();

console.log("first label is " + labels[0].name)
console.log("second label is " + labels[1].name)
console.log("last label is " + labels[labels.length-1].name)
console.log("number of labels is " + labels.length)

https://codepen.io/snorkltv/pen/GRJgJBL?editors=0011

 

In GSAP 3 we get a labels object, which admittedly I'm not as familiar working with.

Below is a pen setup with GSAP3 if someone could fill in the console logs that would be very helpful

 

See the Pen rNVaVYy by snorkltv (@snorkltv) on CodePen

 

 

Share this post


Link to post
Share on other sites

Hey Carl. Depending on your needs you can sort the object in different ways:

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

 

This might be a place where a helper method of some sort would be useful because the object is admittedly harder to work with. What do you see the common use cases being? What sort of method would be the most helpful?

Share this post


Link to post
Share on other sites

Thanks, for the speedy reply. That's definitely the type of stuff I found on stackoverflow that scared me into posting here. Having an array in v2 served my needs perfectly. I guess I'm struggling to see the advantage of the new object approach now that I'm trying to do something with it. I sense Jack chiming in soon ;)

 

Share this post


Link to post
Share on other sites
3 minutes ago, Carl said:

I sense Jack chiming in soon ;)

He's AFK right now but I already notified him about this post. There are several things pulling our attention today though so it might be some time :) 

  • Like 1

Share this post


Link to post
Share on other sites

NP. thanks for the update.

 

BTW below is an example of what I'm working on for a lesson. It's done in V2. 

The idea is to show how easy it can be to do basic timeline navigation using tweenTo() with nextLabel() and previousLabel(). Notice how when you run out of labels going forward it takes you back to the first label and it loops the other way clicking on previous. Fairly trivial when working with an array of labels.

 

See the Pen jOPEbwL?editors=0011 by snorkltv (@snorkltv) on CodePen

Share this post


Link to post
Share on other sites

Here's why I shifted to a simple labels object in v3: 

  • Reduce kb. I highly doubt even 0.1% of users would need getLabelsArray() and it's super easy to do with an external helper function (below)
  • Reduce API surface area
  • It's faster and simpler for people to figure out the time associated with a label - instead of calling some helper function like getLableTime(), they can simply do timeline.labels.whatever. Done. 
  • Everything was stored in a labels object anyway in v2, so the plumbing is identical. I just changed it from "_labels" (underscore indicating private) to "labels".

That being said, here's a simple helper function that'll give you the same results as in v2: 

function getLabelsArray(timeline) {
  let labels = timeline.labels,
      a = [],
      cnt = 0,
      p;
  for (p in labels) {
    a[cnt++] = {time: labels[p], name: p};
  }
  a.sort((a,b) => a.time - b.time);
  return a;
}

Does that help? 

  • Like 3

Share this post


Link to post
Share on other sites

Thanks for the explanation and helper function. I still think removing the ability to access a label via its index in an array is something that should be baked-in.

 

It's nice that the reasons for its removal and helper function are documented here.

  • Like 1

Share this post


Link to post
Share on other sites

Here's an even shorter, more modern version of that function:

const getLabelsArray = timeline => Object.keys(timeline.labels).map(v => ({name: v, time: timeline.labels[v]})).sort((a,b) => a.time - b.time);

 

22 minutes ago, Carl said:

I still think removing the ability to access a label via its index in an array is something that should be baked-in.

Can you elaborate a bit on that? Why do you think it's worth the kb and expanded API surface area? Do you think this is a common thing that a lot of people need and they wouldn't be able to find/make/use the helper function? I don't recall many questions in these forums that show it's a high-demand kinda thing, but maybe that's just because people don't know they can ask here. Are you seeing demand for it in other circles? 

  • Like 1

Share this post


Link to post
Share on other sites
2 hours ago, GreenSock said:

Here's an even shorter, more modern version of that function:


const getLabelsArray = timeline => Object.keys(timeline.labels).map(v => ({name: v, time: timeline.labels[v]})).sort((a,b) => a.time - b.time);

 

 

@Carl I know you are trying to focus on the animation part in your lessons, but I think that function is a JS fundamental. Well,

everything except the sort part as that is more advanced. But definitely the keys and map part.

let myArray = Object.keys(obj).map(key => obj[key]);

 

That's the same as doing Object.values.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values

 

And according to your demo, you really don't even need the label names. You just need the times, right? So this might be much simpler for your use case.

let labelsArray = Object.values(tl.labels).sort();
let index = 0;

tl.tweenTo(labelsArray[index++]);

 

 

 

  • Like 3

Share this post


Link to post
Share on other sites

 

23 hours ago, GreenSock said:

Can you elaborate a bit on that? Why do you think it's worth the kb and expanded API surface area? Do you think this is a common thing that a lot of people need and they wouldn't be able to find/make/use the helper function? I don't recall many questions in these forums that show it's a high-demand kinda thing

Any time you remove something people are used to you're going to get some pushback. Look at className tweens. We didn't think those made much sense but it now seems people came to rely on them and structure their projects around them. Filesize and API surface area really aren't big concerns for me. I'd gladly sacrifice those for the convenience. I'm guessing you didn't see many questions about getLabelsArray() because it was intuitive and easy to use. It's one of those things that when people realize they need something like it they go to the docs and voila it's right there and it works as they expect. Time will tell if more people actually miss it. The helper function is a good enough solution for now. thx.

 

 

Hey @OSUblake Thanks for chiming in. I ALWAYS appreciate your perspective and advice.

In addition to focusing on animation I try really hard to keep the entry level low and make everything I teach look really easy or at least not scary. I'm always thinking of how I would teach these things to 7th graders. I love the moments of being able to say: "Oh you want to do x? GSAP has a method for that. Look what this one line of code does..."

 

On the other-hand I'm not going to deny that map() and Object.values() aren't helpful. I've been thinking of putting a chapter together that contains some of these "things you should know" things. BTW I didn't know about Object.values() that's pretty cool. And yes, I can use the time or labelName in my example. Ultimately I still feel that looping through an array is the easier concept to grasp, maybe i'm just stuck in my old ways.

 

Again, thanks for the suggestions! I'm always learning new things from you and this group.

 

 

 

 

  • Like 2

Share this post


Link to post
Share on other sites
On 2/8/2020 at 1:10 PM, Carl said:

In addition to focusing on animation I try really hard to keep the entry level low and make everything I teach look really easy or at least not scary. I'm always thinking of how I would teach these things to 7th graders. I love the moments of being able to say: "Oh you want to do x? GSAP has a method for that. Look what this one line of code does..."

 

Yeah, I know you are trying to make it approachable, and that's hard because people want to jump right into the cool stuff. All I can say is that the majority of questions on this forum usually aren't GSAP questions at all. They mostly seem to be general JavaScript questions. 

 

On 2/8/2020 at 1:10 PM, Carl said:

BTW I didn't know about Object.values() that's pretty cool.

 

It's only been around for a couple of years, so a lot of people don't know about it.

 

On 2/8/2020 at 1:10 PM, Carl said:

Ultimately I still feel that looping through an array is the easier concept to grasp

 

In your demo it does, but having a labels object also has it pros. For example, it is much easier to get and set values in an object because you don't need to use an array index to find the label.

 

//get
var time = tl.labels.myLabel

// set
tl.labels.myLabel = 4;

 

 

  • Like 4

Share this post


Link to post
Share on other sites

I've only just discovered this change. I used to love getLabelsArray, I now have to rewrite my custom timeline scrubber tools.

Its obviously a trade off between ease for the few vs file size for the many, i need to see what else is broken in terms of getNextLabel etc.

  • Like 1

Share this post


Link to post
Share on other sites

@ilovemypixels please do let us know if anything else isn't working as you'd expect. As for getLabelsArray(), were you saying it's particularly painful for you to use the helper function instead (thus prefer it gets added back into the API) or just that you didn't realize the adjustment was necessary? 

 

If we get a lot of feedback about the need for that function, I'm certainly willing to reconsider but it just seems kinda unnecessary. Sometimes my judgment doesn't align with most of the community, though, and there's some compelling reason that I just missed. 

Share this post


Link to post
Share on other sites

I will have to look into it further and let you know, when I update my tools.

If it was me, I would probably separate it out and have timeline helper functions as a seperate js file one can include.

Share this post


Link to post
Share on other sites
1 hour ago, ilovemypixels said:

If it was me, I would probably separate it out and have timeline helper functions as a seperate js file one can include.

What else are you imagining would be in that file besides this helper function?

Share this post


Link to post
Share on other sites

Then maybe it should just be added to the list of helper functions. The code in v2 seems pretty straightforward.

https://github.com/greensock/GSAP/blob/86b54d1c70237daeb754f6be8b5d9ee4f4c9cbe2/src/esm/TimelineMax.js#L400

 

p.getLabelAfter = function(time) {
  if (!time)
    if (time !== 0) {
      //faster than isNan()
      time = this._time;
    }
  var labels = this.getLabelsArray(),
    l = labels.length,
    i;
  for (i = 0; i < l; i++) {
    if (labels[i].time > time) {
      return labels[i].name;
    }
  }
  return null;
};

p.getLabelBefore = function(time) {
  if (time == null) {
    time = this._time;
  }
  var labels = this.getLabelsArray(),
    i = labels.length;
  while (--i > -1) {
    if (labels[i].time < time) {
      return labels[i].name;
    }
  }
  return null;
};

p.getLabelsArray = function() {
  var a = [],
    cnt = 0,
    p;
  for (p in this._labels) {
    a[cnt++] = { time: this._labels[p], name: p };
  }
  a.sort(function(a, b) {
    return a.time - b.time;
  });
  return a;
};

 

  • Like 1

Share this post


Link to post
Share on other sites

I was assuming that as well as getLabelsArray() things like previousLabel(), nextLabel() would have been removed. Looks like that is not the case.

  • Like 1

Share this post


Link to post
Share on other sites
3 minutes ago, ilovemypixels said:

I was assuming that as well as getLabelsArray() things like previousLabel(), nextLabel() would have been removed. Looks like that is not the case.

 

Ha. I didn't realize that either. So the only thing missing is the array part, which can be done using one of the functions above.

  • Like 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.

×