Jump to content
GreenSock

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

Bezier Plugin Animations/TweenMax vs TimelineMax

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

Hi. I'm a Flash guy that's been dabbling in HTML5/Javascript stuff off and on for about a year now. Here's what I'm trying to accomplish:

  • Eight circles of different colors animating in to form a ring (using a bezier curve) with the bottom circles overlapping the top ones (seen in circles.png)
  • Once animated in to position, clicking on one of the circles will animate them until the clicked circle is at the bottom. The layers/zIndex will distribute correctly to match the original layout.

I'm using TweenMax right now to animate the intro and it works pretty well. However, I'm using setTimeout to stop the animations so they stop when they get to the "correct" position to form the ring. This is a little finicky, as they will stop in slightly different positions each time. This leads to my first question: is there a better way stop the animations so the circles stop evenly along the ring?

 

The other part of this is how I'm going about it. Eventually I'll want the animations to go back and forth simultaneously when you click a circle and i'm wondering: will this be done easily using functions of TweenMax like reverse or will TimelineMax be better for this situation?

 

One last question... Here is some of my code:

TweenMax.to( circleArr[0], .5, {
	css:{
		zIndex:0,
		bezier:{
			curviness:1.5,
			values:[ {left:100, top:100}, {left:75, top:75}, {left:100, top:50} ]
		}
	},
	ease:Linear.easeInOut
} );

 

I use the bezier line a few times and I'm wondering if I can simplify it by doing something like:

var bez1 = BezierPlugin.bezierThrough([{left:100, top:100}, {left:75, top:75}, {left:100, top:50}], 1.5);

TweenMax.to( circleArr[0], .5, {
	css:{
		zIndex:0,
		bezier:bez1
	},
	ease:Linear.easeInOut
} ); 

 

I'm submitting a zip file with my work so far. Let me know if you have any suggestions or questions about what I'm trying to do. Thanks!

post-14114-0-84961800-1362596306_thumb.png

Test.zip

Link to comment
Share on other sites

Hi and welcome to the forums,

 

The animation looks very good, congratulations!!

 

The way I'd do it would be to create a timeline with the complete intro animation, you put labels inside(this way you can avoid the setTimeout functions) like this you can use the tweenFromTo and tweenTo methods in order to go a specific label (if desired), check the api for further info. In order to get every circle in the same position all the time the best way would be with a fromTo tween, like that you can control both positions.The timeline will also be very helpful in order to reverse, pause, stop, seek, resume and do a lot more cool things with the animation.

 

And just a couple of suggestions, first the css:{} wrapper is no longer required, the engine detects the properties and send them to the css plugin.

myTween = TweenMax.to( circleArr[0], .5, {
     zIndex:0,
     bezier:
     {
          curviness:1.5,
          values:[ {left:100, top:100}, {left:75, top:75}, {left:100, top:50} ]
     }
});

Second update to the newest version (1.9) and finally in order to get things a little more simpler you could use a javascript framework like JQuery or Prototype, specially considering the event handlers and crossbrowssing it could make your life quite easier.

 

Hope this helps,

Cheers,

Rodrigo.

Link to comment
Share on other sites

Thanks for the suggestion! This helped out a lot and helped minimize my code. I'm using the tweenTo function, but I'm having an issue.

 

My circle is set up fairly simply (I attached a new image to show the times). When the animation gets to the end, I can't get it to restart, and I'm not sure how to determine how much further to go. So, for example, if the circle at .75 needs to rotate to .125 in a clockwise rotation, it will go to it's completion at 1 second, and then stop. I've tried resume, restart, and some combination of seek/play in its onComplete function, but it won't restart for the beginning at 0 seconds. I've also tried setting repeat to -1 in the initialization of the timeline. I noticed in the API it says:

 

 

Note that tweenTo() pauses the timeline immediately before tweening its time(), and it does not automatically resume after the tween completes.

 

I'm wondering if that has anything to do with it, and if labels would be of more use than I realize. Either way, here's my updated code:

 

window.onload = function() {
	timeline.pause();
	for (var i = 1; i < 9; i++) {
		var cir = document.getElementById('circle' + i);
		cir.addEventListener('click', circleClick);
		circleArr.push(cir);
		var tempTimeline = new TimelineMax({
			//repeat:-1,
			onComplete:resetTimeline,
			onCompleteParams:["{self}"]
		});
		tempTimeline.to( circleArr[i-1], .5, { 
			zIndex:0, 
			bezier:{
				curviness:2,
				values:[ {left:100, top:100}, {left:75, top:75}, {left:100, top:50} ]
			},
			ease:Linear.easeInOut
		} )
		.to( circleArr[i-1], .5, {
			zIndex:8,
			bezier:{
				curviness:2,
				values:[ {left:100, top:50}, {left:125, top:75}, {left:100, top:100} ]
			},
			ease:Linear.easeInOut
		} );
		timeline.add(tempTimeline, 0);
	}
	moveCircles(0);
	//timeline.play();
	setTimeout( function() { moveCircles(-3); }, 1500);
}

function moveCircles(offset) {
	var tempArr = timeline.getChildren();
	for (i = 0; i < 8; i++)
		tempArr[i*3].tweenTo(1.125 - .125 * (offset + i + 1));
}
			
function resetTimeline(tl) {
	//tl.pause(0);
	tl.seek(0);
	//tl.play(.1);
	//tl.restart();
	//tl.play();
	//tl.resume();
}

post-14114-0-27549000-1363005658_thumb.png

Link to comment
Share on other sites

Are you saying you want it to go PAST the end? Timelines and tweens don't allow that - for example, if you have a 1-second timeline and you try to jump to a time of 2, it'll just stop at 1 (because you can't seek() to a time that doesn't exist). 

 

However, you could use a method like this to cause things to wrap:

 

function tweenTo(timeline, time, vars) {
    if (vars == null) {
        vars = {};
    }
    var duration = timeline.duration(),
        proxy = {time:timeline.time()};
    vars.onUpdate = function() {
        timeline.time(proxy.time % duration);
    }
    vars.time = (typeof(time) === "string") ? timeline.getLabelTime(time) : time;
    vars.ease = vars.ease || Linear.easeNone;
    timeline.pause();
    return TweenLite.to(proxy, Math.abs(time - proxy.time) / timeline.timeScale(), vars);
}

Then, all you'd need to do is call that function and feed in the timeline and target time (or label):

 

//if your timeline is 10 seconds, for example, this will to all the way to the end and then loop back around and play it to the halfway point
tweenTo(yourTimeline, 15);

Is that what you're looking for? 

 

The key is simply that we're using the modulus operator when we set the time() or seek() so that the value never exceeds the duration. 

  • Like 3
Link to comment
Share on other sites

Here is an example to help you visualize Jack's suggestion:

 

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

 

It takes a timeline that is 3 seconds long and tweens it to a time of 4.5 seconds which has the effect of it playing 1.5 times. 

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

×