Jump to content
GreenSock

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

Need some hover Play() / Reverse() approach help

Go to solution Solved by Jonathan,

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

 

So here is my example, i extremely simplified it, so please don't judge clumsy logic, in fact it's very complicated animation framework)

 

My issues is very simple...If you try to hover on twitter icon fast than you'll see that twitter icon color haven't reversed completely on mouse-out before mouse-over call have started from scratch.

 

What i need is to stay in logic of Play() / Reverse() on hover, but if there is mouse-over call and tween is still reversing on current target - than it should get reversed to the end and only then get played from start so it won't loose initialized colors on first launch.

 

Please, any help with that?

See the Pen kLwda by failure13 (@failure13) on CodePen

Link to comment
Share on other sites

The problem is essentially that inside your mouseenter svgAnim() method you are executing a whole lot of unnecessary and redundant code. Specifically you are creating a new timeline and adding new tweens to it on every mouseenter. The better approach is to create the timeline animation for each element once when your app initializes and then on mouseenter / mouseleave simply toggle the playing and reversing of that animation.

 

In short, separate the animation creation code from the mouseenter event. 

 

Rodrigo, provides a super simple example of this technique here:

 

http://codepen.io/rhernando/pen/yLeIt?editors=011

  • Like 1
Link to comment
Share on other sites

Hey man, thx for reply...But i guess it's really not an option for a very huge AngularJS project, with ~40k probable elements to animate + dynamical content it will just explode client to precreate those tweens, that's exactly why i'm doing it specifically only when requested by mouseenter or some other event, it's the only way to deliver cool and complex animations without creating perfomance disaster as far as i can see here :(

 

So it's not an answer for my specific case sadly.

Any other advice / technique on core question?

Link to comment
Share on other sites

Adjust your logic then so that on mouseenter you check to see if a timeline animation exists on that element, if not create it and play it. If it does exist than simply play it.

  • Like 2
Link to comment
Share on other sites

Well, that's exactly what i was trying to do for whole day, can you please fork my codepen and give example of how to apropriately do this so that you can't trick it with fast hover in-outs?

 

I was trying stuff like if (isActive()), if (!paused()), if (reversed()) etc, they all seem to fail, maybe i was doing something wrong.

Link to comment
Share on other sites

to check if the timeline exists you would do 

 

if(aTwn.svgTintHover) {
    console.log("tween exists")
    aTwn.svgTintHover.timeScale(1);
    aTwn.svgTintHover.play();
  } else {
// other stuff to create the timeline and play it for the first time
}

 

http://codepen.io/anon/pen/oeIBF?editors=001

Link to comment
Share on other sites

Cool man, it works!

But only for one...

If i add another target you would get such effect:

See the Pen fsdzG by failure13 (@failure13) on CodePen

 

That they both have common tweeen...

 

Is there any way to maybe do something like create TimelineLite for this (though angular seem to have element instead of this, and it gets me confused a lot of times of how to get similar effect like usual this) and then check somehow if this have instance of TimelineLite?

Link to comment
Share on other sites

  • Solution

Hello failure13,

 

To add to Carl's great advice that did all the heavy lifting!  Thanks Carl! :D  ... What you can do is since your passing your element (this) through your hover event handlers. Just use the first argument passed to your svgAnim() function, named object to store your timeline reference, instead of using the var aTwn.

 

Working example (runs on page load, just hover over elements):

 

See the Pen xFjDg by jonathan (@jonathan) on CodePen

 

Basically I switched inside your svgAnim() function:

 

aTwn.svgTintHover to object.svgTintHover

 

So this way, each element stores the timeline inside its own object, relating to each of your hovered element.

 

I hope this helps! :)

  • Like 1
Link to comment
Share on other sites

Jonathan

Excellent!!!

Works awesome man! :)

 

Guys, thank you so much for help, that was extremely stupid logical problem after all))

But i guess only people who doesn't have such kind of stuff are those who doesn't work at all! :D

Thanks again :)

 

Oh yeah, one more question, why i can't just:

            case 'iTwitter':
                    color = "00ABF0"
                break

instead of


            case 'iTwitter':
                    object.svgTintHover.to(aTarget.fill, 0.4, {'fill': '#00ABF0', ease: Quad.easeOut}, 0)
                        .to(aTarget.stroke, 0.4, {'stroke': '#00ABF0', ease: Quad.easeOut}, 0);
                break

Do i need something like invalidate maybe?

Just feeling it's not the best practice here to create whole new tween in my basic TimeLine chain just to change color (for this particular case of use)...

Link to comment
Share on other sites

No worries.. Just store your color  in the same argument named object. Like object.color

 

See the Pen aljEA by jonathan (@jonathan) on CodePen

// store color in object argument
// advanced animation switch
switch (aTarget.svg.parent().attr('vector')) {
   case 'iTwitter':
        object.color = '#00ABF0';
        break
   default:
        object.color = '#A21D20';
}

:

:)

  • Like 1
Link to comment
Share on other sites

Awesome!

But why in previous case TimeineLite have no reaction for global var change?

Just wonder)

 

When it get created it starts to orient & react only for changes of vars from where it have been created?

Link to comment
Share on other sites

Im not sure i understand your question, which global var, and which codepen example are you referring too?

Link to comment
Share on other sites

Oh sorry)

Well, your pen for example, well even my first, doesn't matter

 

See the Pen xFjDg by jonathan (@jonathan) on CodePen

 

I at first i'm passing var red = '#A21D20'; as default color for svgAnim function,

then i create:

object.svgTintHover = new TimelineLite({paused: true, overwrite: 'none'});
object.svgTintHover.to(aTarget.fill, time, {'fill': color, ease: Quad.easeOut})
    .to(aTarget.stroke, time, {'stroke': color, ease: Quad.easeOut}, 0);

 

 

but if then i'd do something like:

            case 'iTwitter':
                    console.log(color);
                    color = '#00ABF0';
                    console.log(color);
                break

 

It will output:

21:46:05.256 "#A21D20"
21:46:05.256 "#00ABF0"

 

But tween would actually use first value when i do object.svgTint.play();

 

Just don't really understand why in this case color = something; doesn't work and object.color = something works..

Link to comment
Share on other sites

That is because object.color is storing the color value in an object namespace that references and is associated with your element this, which is passed to your function as an argument. So you are keeping the scope of each element within your function passed as this, and making sure that object.color is always associated with your element this. Since you are trying to keep track of multiple values for multiple elements with the same class. Versus just keeping track of a global variable that is outside your function.

 

For more information check out:

 

Introduction to Object-Oriented JavaScript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript

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

Working with Objects: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects

 

:)

  • Like 2
Link to comment
Share on other sites

  • 2 weeks later...

There are several ways to go about this in Angular.

 

Option 1:

You can bind the fill color to your scope and then interpolate the color in a directive.

<path fill="{{color}}" />
 


Option 2:

Create a directive for each of your SVGs and put ng-mouse* directives in your SVG attributes.

 

Plunk

 

http://plnkr.co/edit/2sw5Ys05rVoNpNKMRsMh?p=preview

 


 

Option 3:

While Option 2 works, it's not really efficient because Angular is all about creating reusable components. The Plunk above can be easily modified to handle all your SVGs, all with different colors and times.

 

<icon-svg file-name="twitter.svg" dim-time="0.4" to-time="1.0" to-color="cyan"></icon-svg>
 

Plunk

 

http://plnkr.co/edit/SNdgqm?p=preview

 


 

Notice in the Plunks how type: "svg" is included in the directives. This is new to Angular 1.3, so make sure you are running the latest version before adding it.

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