Jump to content
Search Community

Help with overlapping items on repeat Timeline

Luckyde test
Moderator Tag

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

Hey guys,

I'm really stumped here and i can't figure it out. I'm trying to build a 3d carouselle, but when i use staggerto with delays to make it work on restarting the timeline everything snaps into their positions on initial setup. Is there a way on restarting the timeline to remember where everything in the stagger to is stored and continue from that position to keep looping?

Also side topic but on putting my code in the pen the perspective changes even though the code is exactly the same.

Localhost
http://www.luckyde.com/js/assets/Screen%20Shot%202016-06-02%20at%2011.44.11%20AM.png

(and it breaking) http://www.luckyde.com/js/assets/Screen%20Shot%202016-06-02%20at%2011.44.15%20AM.png
Pen

http://www.luckyde.com/js/assets/Screen%20Shot%202016-06-02%20at%2011.44.24%20AM.png

And i used document.onreadystatechange because on initial load things seemed to snap into their locations and i was trying to find a way to have all the elements in the right place on setup not snap to it.
Ideally i'd like for the timeline to be paused at a location and then on trigger of one of the items it to start spinning to that item(which could work with progress() if i manage to find a way to fix the timeline)

Any ideas on how to fix this?
Thanks!

See the Pen gMbVYo by LuckyDe (@LuckyDe) on CodePen

Link to comment
Share on other sites

Update:

See the Pen pbvMYj by LuckyDe (@LuckyDe) on CodePen


I'm not there yet but ive organised all of the items into seperate timelines now, i need to figure out how to organise all of those timelines into a single timeline and have it on repeat not to pause everything/have the same issue as above. Any suggestions on how to do this? So i have the control to stop pause and move the master timeline into positions?
 

for(var i=0;i<itemCount;i++){
		TweenMax.set(boxes[i], { x: (galleryWidth / 2) - itemWidth / 2,z:0})
		timeLines.push(new TimelineMax({paused:true,repeat:-1}))
		timeLines[i].add( TweenMax.to(boxes[i], SpinTime,   {bezier:{type:"soft", values:circlePath},ease:Linear.easeNone }	));
		timeLines[i].progress(1/itemCount *i)
		timeLines[i].play()
	}

The long winded way of getting the multiple timelines to work

Link to comment
Share on other sites

You don't have to pause an animation during initialization. I see people do that all the time, but it's not going to render until the next computer cycle. You're just wasting computer resources by pausing and playing an animation in the same cycle.

 

For Bezier animations that aren't symmetrical, like yours, changing the progress is the best way to offset them.

 

If you're looking for a clean way to build timelines from an array, check out the Array.prototype.reduce method. It doesn't get much cleaner than this.

See the Pen e950b59669be60ae57cb43550d5192df?editors=0010 by osublake (@osublake) on CodePen

  • Like 2
Link to comment
Share on other sites

Thanks, but again that doesnt really work in this case and I'd really like to not use jQuery just for this issue as it will eat up more filesize for what I'm  building and i need the filesize. Do you have a non jQuery solution possibly?
I just need the timelines to join up into one and have it not snap into different places on repeat and break the timeline

Link to comment
Share on other sites

jQuery is irrelevant. That's just what the demo I linked to happened to be using. But here's how to create an array of elements...

// Using ES6
Array.from(document.querySelectorAll(".box"))

// Without
Array.prototype.slice.call(document.querySelectorAll(".box"))

And it doesn't have to be an array of elements. It could be an array of Beziers or something else. Whatever it is you're working with, it gets accumulated into a timeline, which could then passed into other reduce method, allowing you to create complex timelines with relative ease. I'll try to post an example later.

  • Like 2
Link to comment
Share on other sites

Another way to offset an animation is to use negative delays. The timeline will normalize the time difference so you won't see a delay.

 

Here's how you can create your timeline using map reduce.

var timeline = boxes.map(bezierTween)
  .reduce(buildTimeline, new TimelineMax({ repeat: -1 }));

function bezierTween(box) {
  return TweenMax.to(box, time, { bezier: bezier, repeat: -1 });
}

function buildTimeline(tl, tween, i) {
  return tl.add(tween, i * delay);
}

Demo...

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

  • Like 2
Link to comment
Share on other sites

Awesome demo, again, Blake. 

It always takes me some time to wrap my head around map() and reduce().

 

Now that the timeline is built, I think part 2 is to find a way to create a seamless loop that Luckyde can somehow navigate.

 

At a time of 4 seconds each element is added to the carousel and in position. At a time of 8 seconds one iteration of all the animations has transpired.

 

I created a tween based on timeline.tweenFromTo(4, 8) and put it inside a repeating TimelineMax called "controlTween". I then use that single timeline to jump to different progress() values. 

 

var controlTween = new TimelineMax({repeat:-1})
controlTween.add(timeline.tweenFromTo(4, 8))


function update(){
    controlTween.progress(progressSlider.value).pause();
}


function adjustUI() {
  progressSlider.value = controlTween.progress();
}

controlTween.eventCallback("onUpdate", adjustUI)
progressSlider.addEventListener("input", update);

function tweenTo(progress) {
  controlTween.pause();
  TweenLite.to(controlTween, 0.3, {progress:progress})
}

document.getElementById("purple").onclick = function() {
  tweenTo(0.25)
}

document.getElementById("yellow").onclick = function() {
  tweenTo(0.5)
}

document.getElementById("blue").onclick = function() {
  tweenTo(0.75)
}

document.getElementById("green").onclick = function() {
  tweenTo(0)
}

document.getElementById("resume").onclick = function() {
  controlTween.resume();
}

 

http://codepen.io/GreenSock/pen/yJNMJW?editors=0010

  • Like 2
Link to comment
Share on other sites

Nice job! I saw that CodePen picked it. This is a great example of how to build a timeline controller, something a lot of people struggle with. And using a range slider for the scrubber was a good idea. There's no reason to bring in jQuery UI for something so simple.

 

Map and reduce are fairly new to JavaScript (ES5). They can be confusing at first, but what's going on is pretty simple. They both loop through an array, just like jQuery's each method.

 

Map just maps a collection of things to a new collection. So whatever you return in the map function gets added to a new array. So the map function in my demo is mapping a collection of elements to a collection of tweens.

var boxes  = Array.from(document.querySelectorAll(".box"));
var tweens = [];

for (var i = 0; i < boxes.length; i++) {
  var tween = TweenMax.to(boxes[i], time, { bezier: bezier, repeat: 3 });
  tweens.push(tween);
}

Reduce can be a little harder to understand, but all it's doing is taking a collection of things and reducing to a single thing (sometimes called the accumulator). The accumulator is what you return in the reduce function, and it could be anything, a number, string, array, object, timeline, etc. So the reduce function in my demo is taking a collection of tweens and reducing them into a single timeline.

var tweens = [tween1, tween2, tween3, tween4];
var timeline = new TimelineMax();

for (var i = 0; i < tweens.length; i++) {
  timeline.add(tweens[i], i * delay);
}

Understanding reduce in 1 minute...

https://www.airpair.com/javascript/javascript-array-reduce

  • Like 5
Link to comment
Share on other sites

Well since we already have an array of elements, we could add in on more function to simplify things. I added a data attribute to the box elements, so now we can add event listeners to the buttons like this.

var step  = 1 / boxes.length;

boxes.forEach(handleClick);

function handleClick(element, i) {
  var button = document.querySelector("#" + element.dataset.button);
  button.addEventListener("click", function() {
    tweenTo(i * step);
  });
}

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

Link to comment
Share on other sites

Thank you so much for your help guys!
Sorry for the late reply, i had to rush out the ad so i ended up controlling the multiple timelines at once but for the next project I'll know to use your refferences as guides on organising it all into a single timeline, I really appreciate the 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...