Jump to content
Search Community

Best way to apply a modifier tween on multiple targets?

Johan ⚡️ Nerdmanship test
Moderator Tag

Go to solution Solved by OSUblake,

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'm using Blakes clever method of using a mouse object to update a modifier function (

See the Pen 4160082f5a86a3cd0410fb836a74fa68 by osublake (@osublake) on CodePen

), but in my case I have multiple targets. It feels like a pretty common use case, so I assumed there's a good practise to do it.

 

In the example I want the boxes to follow the mouse movement depending on their respective index in the collection. The pen works, but I wonder if there's a way to do it without a for loop, like the way you can with "function based values".

 

This is what I've got: (pen)

// A collection of five boxes
const boxes = document.querySelectorAll(".box");

// Mouse object as input in modifier function
const mouse = { x: 0 }

// Bind mouse to update function
window.addEventListener("mousemove", updateMouseObj);

// Updates mouse object
function updateMouseObj(e) {
  mouse.x = e.clientX;
}

// Working example with for loop
for (let i = 0; i < boxes.length; i++) {
  TweenMax.to(boxes[i], 1, { x: 0, repeat: -1, ease: Linear.easeNone,
    modifiers: {
      x: function() {
        return mouse.x * i;    
      }
    }
  });
}

/*

// Seems lengthy and fragile, Codepen throws an infinite loop error
TweenMax.to(boxes, 1, { x: 0, repeat: -1, ease: Linear.easeNone,
  modifiers: {
    x: function(x, target) {
      for (let i = 0; i < boxes.length; i++) {
        if (target === boxes[i]) {
          return mouse.x * i;    
        }
      }
    }
  }
});


// Would wanna do something like this
TweenMax.to(boxes, 1, { x: 0, repeat: -1, ease: Linear.easeNone,
  modifiers: {
    x: function(i) {
      return mouse.x * i;    
    }
  }
});


// ...like function based values work
TweenMax.to(boxes, 1, { x: function(i) { return 50*i; } });

*/

Thanks! <3
 

See the Pen RKErya by nerdmanship (@nerdmanship) on CodePen

Link to comment
Share on other sites

  • Solution

Funny. I actually asked about being able to pass in indexes to a modifier functions, but that idea only made it to function-based values.
https://greensock.com/forums/topic/14558-feature-request-wrap-values-modulo/?p=63200
 
I'm pretty sure your going to need some type of loop here, unless there's some super crazy es6 way of destructuring it. I know all the cool kids are using "let" and "const" statements nowadays, and here it actually works out because "let" creates a new scope on each iteration. If you replace "let" with "var", it won't work correctly because the i value will be the same for each animation.
 
I've been avoiding using "let" because it can be really slow... and I think it looks stupid, but that's just me.  :-P
 
I've never had a problem with var because I normally don't run a lot of code inside a loop. I usually pass something off to a function, which will create a new scope. 

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


 
Actually, if you look at all the demos I made in that thread, almost every single one is done the same way. I'm using a simple loop to pass some value off to a function, which creates the animation. 
 
.

  • Like 3
Link to comment
Share on other sites

Just thought of this. You could use a function-based value to store the index on the element...

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

TweenMax.to(boxes, 1, { 
  x: (index, target) => {
    target.index = index;
    return 0;
  }, 
  repeat: -1, 
  ease: Linear.easeNone,
  modifiers: {
    x: (value, target) => {
      mouse.x * target.index;
    }
  }
});

.

  • Like 3
Link to comment
Share on other sites

Blake, what a surprise! Let me know if you ever need a kidney.

 

If you replace "let" with "var", it won't work correctly because the i value will be the same for each animation.

 

I noticed this in the project I'm working on, and honestly I had no idea "let" created a new scope on each iteration. After knowing this and studying more of your mentioned pens, I rewrote my code and, as usual, it works better. My brain hurts tho.

 

To me, using the let/const is a first step into ES6 and a little affirmation to myself that I'm not afraid of new syntax (which - of course - I am). Whenever I use var, I feel like I'm resorting to my comfort zone where I develop less. This is clearly not rational. Understanding var on a fundamental level would obviously not set me back. But when I think about it that's probably my main motivation. I bet a lot of people, just like me, don't fully understand what we're doing and why. However, this tend to put me in tricky situations in which I'm forced to learn.

 

Edit: Oh, kind of on the same topic... you said in this post that you wouldn't use mouse position for some values in a real project. Why is that?

  • Like 4
Link to comment
Share on other sites

Stepping outside your comfort zone is good. If you don't, you'll get lazy and never progress.

 

There's a lot of nice things about ES6, I just don't find let/const to be one them. Not because I don't see the value in them, I do. But because they are going to confuse other people, and that's what matters the most.

 

I think the one people will find the most confusing at first is const. Seems so simple. const means it's constant, as you can can't change it, right? Nope. You can change a constant, you just can't reassign it.

const foo = 4;
foo = 5; // => Assignment to constant error

const person = { name: "Bob" };
person.name = "Sally"; // => ok
person.age = 50; // => ok

console.log(person); // => { name: "Sally", age: 50 }

That one definitely messed with my head!

 

 

Edit: Oh, kind of on the same topic... you said in this post that you wouldn't use mouse position for some values in a real project. Why is that?

 

I guess I could have worded that better. Most of the demos I made in that thread were based on mouse movement, and I was acknowledging that in general, most projects do not use mouse based animations. So I was trying to make a point that a lot of the stuff I was doing would work the same without a mouse. I didn't want people to think that the only use for the plugin would be for mouse animations.

 

 

.

  • Like 3
Link to comment
Share on other sites

I worship your input as a divine scripture. Thanks again for sharing!

 

Since you shared the technique of map func, modifiers and storing values in an object I've not only been writing better code, but thinking more creatively about animations. I don't see many reasons not to use modifiers at the moment.

I recommend anyone reading to check out Blake's forum posts about norm, lerp and map functions here, how he updates a tween with modifiersPlugin in 

See the Pen 89e929cd4cdb6dae68186f08f026f363 by osublake (@osublake) on CodePen

 and how he combines map and modifier in

See the Pen 4160082f5a86a3cd0410fb836a74fa68 by osublake (@osublake) on CodePen

.

 

✌️

  • Like 3
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...