Jump to content
Search Community

How to manage multiple Timelines ?

farhoudz test
Moderator Tag

Go to solution Solved by OSUblake,

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

Here I have three Timelines which I play and reverse them in appropriate cases :

var firstSwipeRight = new TimelineMax({
        paused: true
    })
    .fromTo(firstChanel, 0.1, {
        left: 0
    }, {
        left: offset
    }, "firstSwipe")
    .fromTo(".dot", 0.1, {
        right: "26px",
        scaleX: 1
    }, {
        right: "147px",
        scaleX: 3
    }, "firstSwipe")
    .to(".dot", 0.2, {
        scaleX: 1
    })
    .fromTo(firstChanel, 0, {
        visibility: "visible",
        display: "block"
    }, {
        visibility: "hidden",
        display: "none"
    }, "firstSwipe+=0.1")
    .fromTo(secondChanel, 0.1, {
        visibility: "hidden",
        display: "none"
    }, {
        visibility: "visible",
        display: "block"
    }, "nextChanel")
    .fromTo(secondChanel, 0.1, {
        left: -offset
    }, {
        left: 0
    }, "nextChanel+=0.1");
    
var secondSwipeRight = new TimelineMax({
        paused: true
    })
    .fromTo(secondChanel, 0.1, {
        left: 0
    }, {
        left: offset
    }, "firstSwipe")
    .fromTo(".dot", 0.1, {
        right: "145px",
        scaleX: 1
    }, {
        right: "266px",
        scaleX: 3
    }, "firstSwipe")
    .to(".dot", 0.2, {
        scaleX: 1
    })
    .fromTo(secondChanel, 0, {
        visibility: "visible",
        display: "block"
    }, {
        visibility: "hidden",
        display: "none"
    }, "firstSwipe+=0.1")
    .fromTo(thirdChanel, 0.1, {
        visibility: "hidden",
        display: "none"
    }, {
        visibility: "visible",
        display: "block"
    }, "nextChanel")
    .fromTo(thirdChanel, 0.1, {
        left: -offset
    }, {
        left: 0
    }, "nextChanel+=0.1");
    
var directSelect = new TimelineMax({
        paused: true
    })
    .fromTo(firstChanel, 0.1, {
        left: 0
    }, {
        left: offset
    }, "firstStep")
    .fromTo(firstChanel, 0, {
        visibility: "visible",
        display: "block"
    }, {
        visibility: "hidden",
        display: "none"
    }, "firstStep+=0.1")
    .fromTo(secondChanel, 0.1, {
        visibility: "hidden",
        display: "none"
    }, {
        visibility: "visible",
        display: "block"
    }, "secondStep")
    .fromTo(secondChanel, 0.1, {
        left: -offset
    }, {
        left: offset
    }, "secondStep+=0.1")
    .fromTo(secondChanel, 0, {
        visibility: "visible",
        display: "block"
    }, {
        visibility: "hidden",
        display: "none"
    }, "secondStep+=0.2")
    .fromTo(thirdChanel, 0.1, {
        visibility: "hidden",
        display: "none"
    }, {
        visibility: "visible",
        display: "block"
    }, "thirdStep")
    .fromTo(thirdChanel, 0.1, {
        left: -offset
    }, {
        left: 0
    }, "thirdStep+=0.1")
    .fromTo(".dot", 0.1, {
        right: "26px",
        scaleX: 1
    }, {
        right: "266px",
        scaleX: 3
    }, "thirdStep")
    .to(".dot", 0.2, {
        scaleX: 1
    });

As you can see some targets are the same in all three Timelines, I manage to use these Timelines like this:

element.on("click", ".tabs", function (event) {

    target = event.currentTarget;            
    i = Array.prototype.indexOf.call(target.parentNode.children, target);           
    dotPos = $(".dot").position();            
    leftPos = dotPos.left;

    // How to prevent conflicts between my Timelines in all below cases?            
         
if (i === 0 && leftPos === 145) {                
firstSwipeRight.totalProgress(1).reverse();} 

else if (i === 0 && leftPos === 26) {                
directSelect.totalProgress(1).reverse();} 

else if (i === 1 && leftPos === 266) {                
firstSwipeRight.totalProgress(0).play();} 

else if (i === 1 && leftPos === 26) {                
secondSwipeRight.totalProgress(1).reverse();} 

else if (i === 2 && leftPos === 266) {                
directSelect.totalProgress(0).play();} 

else if (i === 2 && leftPos === 145) {                
secondSwipeRight.totalProgress(0).play();}

});

The problem is that as I use .totalProgress() method to somehow set each Timeline head on the start or end position to play or reverse them without conflict, I still has conflicts in some properties like display and visibility for example and this conflict happens when I use first and second Timelines and then use the third or some other cases, So what could I do to prevent these conflicts in all cases ? Please Advice.

 

 

 

 

Link to comment
Share on other sites

Hi farhoudz,

I don't have a clear solution for you, but I have a few suggestions that might make your code more compact:

 

The first suggestion would be to use .set() instead of .fromTo() with 0 duration and use autoAlpha for animating visibility of your elements.

 



.set(firstChanel, {autoAlpha: 0})


In terms of managing multiple timelines, I prefer to create one main timeline and then add sub-timelines to it together with a label.

 



function getYourTl(){
var yourTl = new TimelineMax();

yourTl
.to(elem, 1, {vars})
.fromTo(elem, 1, {fromVars}, {toVars});

return yourTl;
}

mainTl.add(getYourTl(), 'scene-one');


 

You can then seek to a specific time or label on the mainTl and play or reverse accordingly.

 

Hope that helps.

 

Cheers

Petr

@ihatetomatoes

  • Like 4
Link to comment
Share on other sites

Thank you Ihatetomatoes, I use your technics and read your articles every day and they are awsome,

 

About your solution I have edited my code like this:

function fsr() {
        var firstSwipeRight = new TimelineMax({})
        
        .fromTo(firstChanel, 0.1, {
            left: 0
        }, {
            left: offset
        }, "firstSwipe")
        .fromTo(".dot", 0.1, {
            right: "26px",
            scaleX: 1
        }, {
            right: "147px",
            scaleX: 3
        }, "firstSwipe")
        .to(".dot", 0.2, {
            scaleX: 1
        })
        .fromTo(firstChanel, 0, {
            visibility: "visible",
            display: "block"
        }, {
            visibility: "hidden",
            display: "none"
        }, "firstSwipe+=0.1")
        .fromTo(secondChanel, 0.1, {
            visibility: "hidden",
            display: "none"
        }, {
            visibility: "visible",
            display: "block"
        }, "nextChanel")
        .fromTo(secondChanel, 0.1, {
            left: -offset
        }, {
            left: 0
        }, "nextChanel+=0.1");

        return firstSwipeRight;
    }

And here is my master Timeline:

var chanelAnim = new TimelineMax({

            paused: true

        }),

        firstSwipe = fsr(),
        secondSwipe = ssr(),
        directSelection = ds();

    chanelAnim.add(firstSwipe, "scene-one")

    .add(secondSwipe, "scene-two")

    .add(directSelection, "scene-three");

And I use them like this:

chanelAnim.seek("scene-one").play(0);

or:

chanelAnim.seek("scene-one").reverse(0);

But the problem is that this code plays all the Timelines together I think and I really do not know why, Am I wrong at some point?

 

Please advice,

 

Farhoud

Link to comment
Share on other sites

Hi Farhoud,

can you setup a simplified CodePen demo with what you are trying to do?

 

From quickly looking at your code, your first function should look like this:

function fsr() {
    var firstSwipeRight = new TimelineMax({});
    
    firstSwipeRighdt.fromTo(firstChanel, 0.1, {
        left: 0
    }, {
        left: offset
    }, "firstSwipe");

    return firstSwipeRight;
}

Cheers

Petr

  • Like 1
Link to comment
Share on other sites

Dear Ihatetomatoes,

 

Here is exactly what I am trying to do:

 

See the Pen xGmVqW by fzolhayat (@fzolhayat) on CodePen

 

As you can see there are three tabs which If you click on each one of them it has to animate you to the corresponding .col element and in addition it has to animate the location of .dot element to show you which element you have chosen, I have also used hammer.js in my real project to activate swipe event on mobile devices on each .col element so whether the user clicks on each tab or swipes on each .col element it has to animate to the right element and all of the Timelines has to be synced but the problem is that :

 

1 - it plays all of the Timelines together as I can guess

 

2 - I think all of my Timelines has conflict which each other as they have common tweens and if for example you play directSelect Timeline and want to reverse secondSwipeRight Timeline then there is a problem

 

I hope I could explain my problem clearly, It's all a matter of managing multiple Timelines.

 

Regards and thanks in advance.

Link to comment
Share on other sites

Hi Farhoud,

 

My guess is that you want to animate each element when clicking on a specific tab, right?. Basically remove the current visible element and animate in the one corresponding to the clicked tab.

 

In this case I don't see a good use of nesting all timelines in a parent one, that's more useful when in fact all timelines have to be played or controlled in a sequence, for example when you could be using a scroll site like this:

 

http://journey.lifeofpimovie.com/

 

That basically works with a bunch of timelines nested into one that is controlled with the scroll position of the main container.

 

The approach I'd suggest you is to create a timeline for each element and play/reverse that one and the target one depending on the click event. I've created this simple example, feel free to fork and adapt it to your scenario:

 

See the Pen JdwKKq by rhernando (@rhernando) on CodePen

 

As you can see the first element is the visible/active one so that particular timeline's playhead is moved to it's end:

tl1.("#box1", 1, {vars}).pause(tl1.duration());

And the first element has an active class that makes selecting easier.

  • Like 4
Link to comment
Share on other sites

Thank you Rodrigo for your effort but my case is a little different, I have edited my codepen sample:

 

See the Pen xGmVqW by fzolhayat (@fzolhayat) on CodePen

 

As you can see it is working alot better now but I still have some problems in some cases:

 

- Case one: Select tab two then tab three and then tab one; Here you can see a conflict between Timelines which results in "firstChanel" left position to be animated correctly but remain at "display: none; and visibility: hidden;" state so from user's point of view nothing happened or something bad happened.

 

- Case two: Directly select tab three and then tab two; Here you can see that same problem happened plus all tabs are some kind of disabled and none of the Timelines respond to click event.

 

So by conflict I mean these cases, I may also recall that I created directSelect Timeline because I want the client too see that there is a column between tab one and tab three.

 

Regards and thank you for helping me solve this problem.

Link to comment
Share on other sites

  • Solution

Rodrigo's advice is pretty sound. You're trying to use your timelines like some type of animation manager or controller. Try to break down what you are trying to do into steps, and then create your animation from that.
 
Here's how I see it. Given that you are on a current page and you want to animate to a selected page sequentially. 

 

- The current page will move offscreen

- Any pages in between will move onscreen and then offscreen

- The selected/last page will move onscreen

 

By using the index of the current and selected pages, we can create a range of pages that need to be animated. Now we can setup a timeline that will follow the steps listed above.

 

I added some extra pages to show it animating the pages in between.

 

See the Pen 2f5b1274280a9c147173f7fc498238de by osublake (@osublake) on CodePen

  • Like 3
Link to comment
Share on other sites

Here's the example from your PM. I'm not too familiar with Hammer, but to access properties or methods of the channel object, you need to return an object with whatever you want to be public on it. Before it was just returning an element. If you're not familiar with what I did, go lookup closures and the revealing module pattern because I don't think I can explain it that well. I use it in a lot of my CodePen demos as an easy way to create a class without using 'this' or prototype.

 

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

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