Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
Dylan Cristy

How to get animation playing again normally after element was dragged?

Recommended Posts

I am working on some concentric circles that should rotate infinitely, until a user clicks on one of them, in which case it should stop the animated rotation and be draggable (rotation).  Then, if a different circle is clicked, the new one should stop it's animation, but the previous one should start up again from the position where the user left it after dragging, but with it's original direction and speed.

 

I have managed to get the pausing/unpausing behavior working correctly, except for the fact that if the user drags a band a lot (say, rotating it around fully 2 or 3 times in the same direction), when the animation restarts, it's either going the wrong speed, or the wrong direction, or both.

 

The animation is this:

export const bandRotation = (element, rotateDir, rotateSpeed) => {
	const rotateDeg = rotateDir === "right" ? 360 : -360;
	const tl = new TimelineLite();
	tl.to(element, rotateSpeed, {
		transformOrigin: "50% 50%",
		rotation: rotateDeg,
		repeat: -1,
		ease: Linear.easeNone
	});
	return tl;
};

 

I've tried a couple different ways of stopping and starting it:

 

if (this.props.paused) {
	this.state.rotation.kill();
} else {
	this.setState({
		rotation: bandRotation(this.band, this.props.direction,	this.props.speed)
	});
}

 

and:

 

if (this.props.paused) {
	this.state.rotation.pause();
} else {
	this.state.rotation.invalidate();
	this.state.rotation.restart();
}

 

both of which I would think would restart the animation normally, but again, it's either going the wrong speed, wrong direction, or both.

 

What can I do to ensure the animation restarts with the same speed and direction, no matter how the user drags the circle/band while the animation is paused?

 

See the Pen by s (@s) on CodePen

Link to comment
Share on other sites

I was about to respond to your other post...

https://greensock.com/forums/topic/18743-cant-get-draggable-rotation-to-work-on-svg/?tab=comments#comment-86814

 

First, I had no problems using imports on your demo, so I'm unsure why you were having problems.

 

So here's the problem. When you press on a draggable, it takes control of the rotation, so anything that was animating the rotation will be overwritten.

 

To fix it I would add an onRelease callback to your draggables. Inside that callback, create a new rotation animation. Since the rotation is mostly likely going to be different, you should use relative values.

 

const rotateDeg = rotateDir === "right" ? "+=360" : "-=360";

 

And I'm no react expert, but I probably wouldn't put an animation on the state object. An animation is not a state.

  • Like 4
  • Thanks 1
Link to comment
Share on other sites

50 minutes ago, Dylan Cristy said:

I am working on some concentric circles that should rotate infinitely, until a user clicks on one of them, in which case it should stop the animated rotation and be draggable (rotation).  Then, if a different circle is clicked, the new one should stop it's animation, but the previous one should start up again from the position where the user left it after dragging, but with it's original direction and speed.

 

I just read this, and I don't think I fully understand the behavior you described, so I'm unsure if you need the onRelease callback. The important thing is that you create a new animation using a relative value.

 

  • Like 1
Link to comment
Share on other sites

Thanks @OSUblake!

 

Yeah, for some reason when I try to use imports I get a "_gsap.TimelineLite is not a constructor" error in my animations.js file.

 

You are right about state, I am just used to storing stuff in state, but I could just make a class property called "rotation" and store the animation there.

 

And yes, the relative values for rotation seem to have fixed the problem.

 

As far as the behavior, I am already using the onPress to stop the animation (indirectly*), but I don't want it to start up automatically on onRelease, it should only start up if the user clicks/touches a different band to pause that animation.  So in my demo, when it loads, all three bands are animated and rotating, but once you start interacting with it, only two bands will ever be animated, whichever one you last touched will be draggable (and standing still, if you are not actively dragging it).

 

* The onPress invokes a function on a parent component (that was passed down through props) to set the state of the parent component, which is keeping track of "which is the currently paused band?".  That information is also passed down to all the bands via props, and they use that to know if they should be paused or not.

  • Like 1
Link to comment
Share on other sites

29 minutes ago, Dylan Cristy said:

Yeah, for some reason when I try to use imports I get a "_gsap.TimelineLite is not a constructor" error in my animations.js file.

 

Oh, I see. I wouldn't import from "gsap" anymore.

import { TimelineLite, Linear } from "gsap/all";

// Or 
import { Linear } from "gsap/TweenLite";
import { TimelineLite } from "gsap/TimelineLite";

 

Check out the docs for more info about importing

https://greensock.com/docs/NPMUsage

 

And this thread.

 

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