Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
bg-scro

Start/Stop timeline when element is hovered on

Go to solution Solved by bg-scro,

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

Having some trouble grokking how to get the timeline to stop when I hover over the animated element with the mouse. Essentially, what I want is for the animation to stop spinning and the arrow to point south (180-deg) when user moves the mouse over it.

 

Here is the codepen: 

 

Based on the discussion in another forum post here, I assumed that code like the following would work, but the element shows no sign of responding to mouse events. (Note that `needleSpin` is the animation that runs when the page loads - it works fine; the `pointSouth` animation is what I want to occur when the mouse rolls over the `needle` element).

needle.onRollOver = function() {
  needleSpin.pause();
  pointSouth.play();
};

Appreciate the help...

See the Pen gaNOOY by bg-scro (@bg-scro) on CodePen

Link to comment
Share on other sites

There were a couple of issues, most fundamentally, you hadn't loaded the jquery library in codepen.

JQuery is a bit overkill anyway so i removed your document.ready(); call, and replaced it with:

<body onload="init()">

 

init(); simply calls needleSpin.play();

 

I used a javascript mouseover event listener to detect the hover, and then paused/played the relevent timeline.

take a look below.

 

See the Pen wKLaoZ by JonnyS (@JonnyS) on CodePen

 

J.

  • Like 1
Link to comment
Share on other sites

Hello bg-scro, and Welcome to the GreenSock Forum!

 

Try this:

 

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

 

If you didn't want to use the jQuery ready() method, you could use the native JavaScript equivalent DOMContentLoaded

// wait until DOM is ready
document.addEventListener("DOMContentLoaded", function(event) {
    
});

You can add paused: true to your pointSouth TimelineMax instance so it doesn't run immediately, unless that is what you wanted to do?

var pointSouth = new TimelineMax({paused:true});

Also if you want it to rotate to the south, meaning 180 degrees, without having to spin all the way around. You can use the most shortest rotation path by using the _short suffix

// uses the most shortest path to the rotation point
pointSouth.to(needle, 0.5, {rotation: "180_short"});

// rotates to 180 counter-clockwise
pointSouth.to(needle, 0.5, {rotation: "180_cw"});

// rotates to 180 clockwise
pointSouth.to(needle, 0.5, {rotation: "180_cc"});

And onRollOver is not a valid event handler in JavaScript, unlike in ActionScript. So you can use mouseenter instead. The difference between mouseenter and mouseover is that mouseenter does not use event bubbling.

// hover over
needle.addEventListener('mouseenter', function() {
  needleSpin.pause();
  pointSouth.play();
});

// hover out
needle.addEventListener('mouseleave', function() {
  
});

Then everything together like this:

 

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


 

var needle = document.getElementById("hero-compass-needle");

var needleSpin = new TimelineMax({delay: 1, repeat: -1, repeatDelay: 5});

needleSpin
  .add("startFirstSpin")
  .to(needle, 2.0, {rotation: "+=1480", ease: Power4.easeIn})
  .to(needle, 1.0, {scale: 0.6, ease: Power2.easeIn}, "startFirstSpin+=1.0")
  .add("endFirstSpin")
  .to(needle, 1.0, {scale: 1}, "endFirstSpin")
  .to(needle, 1.75, {rotation: "+=1400", ease: Elastic.easeOut}, "endFirstSpin");

// wait until DOM is ready
document.addEventListener("DOMContentLoaded", function(event) {
  needleSpin.play();
});

var pointSouth = new TimelineMax({paused:true}); // adding paused true so it does not run right away
pointSouth.to(needle, 0.5, {rotation: "180_short"}); // use the most shortest rotation path

// hover over
needle.addEventListener('mouseenter', function() {
  needleSpin.pause();
  pointSouth.play();
});

// hover out
needle.addEventListener('mouseleave', function() {
  
});

In codepen you really don't need to include the html and body tag, since your code is added in the body tag.

 

You can find out more information on directionalRotation in the CSSPlugin Docs:

 

http://greensock.com/docs/#/HTML5/GSAP/Plugins/CSSPlugin/

  • directionalRotation
    Tweens rotation in a particular direction which can be either clockwise ("_cw" suffix), counter-clockwise ("_ccw" suffix), or in the shortest direction ("_short" suffix) in which case the plugin chooses the direction for you based on the shortest path. For example, if the element's rotation is currently 170 degrees and you want to tween it to -170 degrees, a normal rotation tween would travel a total of 340 degrees in the counter-clockwise direction, but if you use the _short suffix, it would travel 20 degrees in the clockwise direction instead. Example:
    TweenLite.to(element, 2, {rotation:"-170_short"});
    //or even use it on 3D rotations and use relative prefixes:
    TweenLite.to(element, 2, {rotation:"-170_short", rotationX:"-=30_cw", rotationY:"1.5rad_ccw"});
    
  • Notice that the value is in quotes, thus a string with a particular suffix indicating the direction (_cw, _ccw, or _short). You can also use the "+=" or "-=" prefix to indicate relative values. Directional rotation suffixes are supported in all rotational properties (rotation, rotationX, and rotationY); you don't need to use directionalRotation as the property name. There is a DirectionalRotationPlugin that you can use to animate objects that aren't DOM elements, but there's no need to load that plugin if you're just animating css-related properties with CSSPlugin because it has DirectionalRotationPlugin's capabilities baked-in.
  • Check out an 

    See the Pen jiEyG by GreenSock (@GreenSock) on CodePen

    .
  • Prior to version 1.9.0, directionalRotation was called shortRotation and it only handled going in the shortest direction. The new directionalRotation functionality is much more flexible and easy to use (just slap a suffix on the regular property).

Let us know if you have any more questions?

 

Does this help :)

  • Like 3
Link to comment
Share on other sites

  • Solution

Thanks much!!

 

@Jonny - Thanks for fixing my Javascript...still getting the hang of the language.

 

@Jonathan - thank you for the very quick an detailed walkthrough.

 

Here's my final solution: 

See the Pen BogoWK by bg-scro (@bg-scro) on CodePen

function init() {
  needleSpin.play();
}

// Animation for compass needle on site hero
var needle = document.getElementById("hero-compass-needle");
var needleSpin = new TimelineMax({delay: 1, repeat: -1, repeatDelay: 5});
var pointSouth = new TimelineMax({paused:true});

needleSpin
  .to(needle, 0, {rotation: 0})
  .add("startFirstSpin")
  .to(needle, 2.0, {rotation: "+=1480", ease: Power4.easeIn}) // , ease: Back.easeOut.config(4)
  .to(needle, 1.0, {scale: 0.6, ease: Power2.easeIn}, "startFirstSpin+=1.0")
  .add("endFirstSpin")
  .to(needle, 1.0, {scale: 1}, "endFirstSpin")
  .to(needle, 1.75, {rotation: "+=1400", ease: Elastic.easeOut}, "endFirstSpin")
;

// Stop and resume spinning needle animation on mouse event; point south
pointSouth
  .add("startHover")
  .to(needle, 1.5, {rotation: "180_short", ease: Power4.easeOut})
  .to(needle, 1.0, {scale: 1}, "startHover")
  ;

needle.addEventListener('mouseover', pauseSpin);
needle.addEventListener('mouseleave', resumeSpin);

function pauseSpin() {
  console.log('pauseMe');
  needleSpin.pause();
  pointSouth.play();
}

function resumeSpin() {
  pointSouth.pause();
  needleSpin.play();
}

Link to comment
Share on other sites

You should opt for using the addEventListener for DOMContentLoaded instead of attaching an inline onload event on the body tag. It is just better practice to have your DOM ready and or window load events in your external JS, rather than having inline event binding.

 

This way your code can have a clean separation of your JS and HTML. And will provide a better overall performance on page load due to:

  • keeping the HTML file size low
  • allow caching of your external JS (whereas body onload is not cached)
  • helps with accessibility (since inline JavaScript can not have a fallback)
  • and keeps your JavaScript code maintenance to a minimum (since you wont have multiple places where your JS resides)

But glad you got it working! Happy Tweening :)

  • Like 2
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.
×