Jump to content
Search Community

Using Flip.fit() with 3D rotation

oliver-halasz test
Moderator Tag

Go to solution Solved by GreenSock,

Recommended Posts

Hi everyone!
I'm really enjoying gsap so far, its capabilities are truly spectacular!
I'm trying to create an effect of a <div> rotated in the 3d space rotates back to the XY plane while simultaneously slides down to match the position of another <div>. The effect I aim to replicate can be found here, more precisely the image on the computer screen rotating and sliding down. 
I want to avoid having to use fixed values for the translation and thought about using Flip.fit() for moving the target element into place together with a scrollTrigger. Alas, it seems as if the 3D rotation is not being considered by the function, resulting in an awkward final state for the sliding element. Does anybody have any ideas on what's going wrong and how I could implement this?

 

See the Pen BaOyejo by oliver-halasz (@oliver-halasz) on CodePen

Link to comment
Share on other sites

  • Solution

Yeah, sorry @oliver-halasz but as stated in the docs: 

Quote

 

Flip does not accommodate 3D transforms (like rotationX, rotationY, or z).

 

It's exponentially more complex to accommodate something like that. Way more code (which everyone would pay the price for even though probably less than 0.001% would ever use/need a feature like that).

 

But since you're animating to a state that doesn't contain any 3D stuff, this should be pretty doable. In fact, here's a helper function that you can replace your Flip.fit() call with: 

function fit2D(fromElement, toElement, vars) {
  let make2D = gsap.set(fromElement, {rotationX: 0, rotationY: 0, z: 0}), // remove 3D stuff
      fitVars = {};
  for (let p in vars) { // copy vars so we can tweak a few things
    fitVars[p] = vars[p];
  }
  fitVars.getVars = true;
  fitVars.scrollTrigger = null;
  fitVars = Flip.fit(fromElement, toElement, fitVars); // don't actually do the fitting - just return the vars object with the necessary x/y/scale stuff to do so
  fitVars.rotationX = fitVars.rotationY = fitVars.z = 0; // we've gotta tween to a state with no 3D
  fitVars.scrollTrigger = vars.scrollTrigger; // restore the ScrollTrigger
  make2D.revert(); // revert the fromElement so that it has its 3D properties again
  return gsap.to(fromElement, fitVars); // tween!
}

And here it is in action: 

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

 

Is that more like what you were looking for? 

  • Like 2
Link to comment
Share on other sites

Goodness, I somehow missed that in the docs ? I was guessing though that it would make the transition too expensive too calculate.
Yes, thank you very much, it's definitely something I can move forward with.
It's so cool that you guys have such an amazing community/support behind an already incredibly powerful library?

  • Like 1
Link to comment
Share on other sites

Quick question: I've noticed in the demo that setting the rotateX property with gsap.set() will result in a different value being used (I'm setting -38deg but the resulting css will contain -21 deg as the initial value) the same goes for the scaleY. Any ideas why this occurs?
No rotation is applied via css to the element, so it's not a conflict with that.

Link to comment
Share on other sites

1 hour ago, oliver-halasz said:

Quick question: I've noticed in the demo that setting the rotateX property with gsap.set() will result in a different value being used (I'm setting -38deg but the resulting css will contain -21 deg as the initial value) the same goes for the scaleY. Any ideas why this occurs?
No rotation is applied via css to the element, so it's not a conflict with that.

Sorry about any confusion there. I updated the CodePen and helper function (added one line) to resolve that. 

 

It's actually a pretty complicated issue related to the fact that Flip.fit() was flagging transforms to get re-interpreted next time GSAP does anything with them. When you've got a matrix3d() (which is what the browser reports whenever you've got any 3D properties), those matrices are inherently ambiguous - you can interpret them in a bunch of different ways. A very simple example would be a rotation of 180 is exactly the same matrix as scaleX and scaleY of -1. So which one should GSAP choose? So in your case, it was interpreting the rotationX differently and mixing that with scaleX and scaleY to get exactly the same appearance. 

 

I've updated the next version of Flip to avoid that situation. But again, I just added a line to the helper function in the demo to work around it in the current version. Let me know if that works okay for you. 

  • Like 1
Link to comment
Share on other sites

Thanks for the fix :) The current animation has the sliding element rotate to 0 kinda late and I was wondering if I could split it into two, so the element will slide downward whilst turning inwards and then fit it into place. When I was trying this solution the end placement becomes off and I'm thinking about how to do this properly:

See the Pen qBMdJWY by oliver-halasz (@oliver-halasz) on CodePen


 

Link to comment
Share on other sites

Yeah, that's because when you call Flip.fit(), the element has 3D transforms applied to it which throws off the fitting. That was kinda the whole point of my first post - you've gotta remove those :) 

 

Is there a reason you didn't use the helper function I built for you that solves all this? 

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

Link to comment
Share on other sites

Hmm, I thought in this case the Flip.fit() would use the stage at the time of the invocation within the timeline, which is after the 3D properties of the sliding image were set to 0. Sorry for the confusion, I'm still a newbie :)
The only reason I wanted to split the animation is that, with only using Flip.fit(), the sliding image turns inward pretty late and sort of look as if it's "free-falling". In the end, I modified the fit2D helper function, so that it returns a timeline.to() tween, which I'm calling after a tween where I'm rotating the image inwards and it now behaves the way I wanted it to :)
Thanks for all your help!

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