Jump to content
Search Community

Combining timelines, tweens, and issues with scroll trigger

vibe9 test
Moderator Tag

Recommended Posts

Hi All,

 

I'm currently trying to combine a couple of different timeline sequences, both of which I've adapted from some others' code pens.

 

 

Right now the issue I have is that once the circle animations finish, I need the box panels to animate up overtop of the space where the circles are in. I can do this by moving the "cards" section into the same section as the circles however then the scroll trigger of each is the same and both animations happen at the same time. What I need is for them to happen essentially in the same space but at different times.

 

I realize there are probably a few ways of going about doing this but my knowledge of Gsap is currently too limited to figure that out.  

 

Ultimately, what I see happening is that the #introBox css position fixed is removed by Gsap once the animation is finished whereas, ideally, either #introBox or #introBoxWrap would get a position fixed once the animation is finished so that the .cards can slide in overtop rather than what happens now which is the last image of the circles scrolls upward (because the parent container is no longer fixed).

 

See the Pen zYJXMNY by vibe9 (@vibe9) on CodePen

Link to comment
Share on other sites

  • vibe9 changed the title to Combining timelines, tweens, and issues with scroll trigger

Hi,

 

I've been looking at your codepen and the markup seems a bit convoluted IMHO, also you have a lot of stuff that could cause some issues, like this:

function part1() {
  window.addEventListener("load", init);
  window.addEventListener("resize", resize);

  function init() {
    imgWidth = img.naturalWidth;
    imgHeight = img.naturalHeight;

    resize();
  }

  function resize() {
    tlintro.progress(0);

    const r = svg.getBoundingClientRect();
    const rectWidth = r.width + pad;
    const rectHeight = r.height + pad;

    const rx = rectWidth / imgWidth;
    const ry = rectHeight / imgHeight;

    const ratio = Math.max(rx, ry);

    const width = imgWidth * ratio;
    const height = imgHeight * ratio;

    const dx = rectWidth / 2;
    const dy = rectHeight / 2;
    radius = Math.sqrt(dx * dx + dy * dy);

    gsap.set(img, { width, height });
    gsap.set(imgFixed, { width, height });

    tlintro.invalidate();

    ScrollTrigger.refresh();
  }
} // end part1

You're adding a load and resize event listeners to the window object inside a function. I never seen that in a case like this so I wouldn't recommend it.

Also there is no need to call ScrollTrigger refresh on a window resize handler, ScrollTrigger does that for you. Same thing with invalidating the animation, you can pass that instruction to ScrollTrigger using invalidateOnRefresh:

Boolean - If true, the animation associated with the ScrollTrigger will have its invalidate() method called whenever a refresh() occurs (typically on resize). This flushes out any internally-recorded starting values.

 

Also your codepen has a lot of warnings because there are some selectors in your JS that don't have the corresponding DOM elements, so GSAP is throwing warnings about that.

 

Finally I can't comprehend what you're trying to achieve with this:

var masterTimeline = new TimelineMax();
masterTimeline.add(part1()).add(part2(), "+=1");

masterTimeline.call(
  function () {
    //addClass, toggleClass, or your custom logic.
    $("#introBoxWrap").addClass("finished");
  },
  null,
  null,
  2
);

Those functions (part1 and part2) don't return anything, so you basically adding nothing to the timeline in that position. Maybe use a call method instead:

https://greensock.com/docs/v3/GSAP/Timeline/call()

 

Also If I was you I'd call those methods in the windows load event, to make sure that the images have loaded.

 

Finally I think this is a far simpler way to achieve what you're looking for:

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

 

Hopefully this helps.

Happy Tweening!

Link to comment
Share on other sites

Thanks for your reply and thoughts @Rodrigo

 

I have a more refined and cleaned up version of the CodePen here

See the Pen PodgXOv by vibe9 (@vibe9) on CodePen

 

As for the load and resize event triggers, those are actually needed to make the circle svg image mask work.  

 

Par1 and Part2 are simply the two timelines that I constructed and then put together in masterTimeline, and that's ultimately where I was having trouble. Ideally there would not be two parts, the pinned layers in part 2 would simply scroll right overtop of the circle layer without it scrolling upward to reveal the background layer below. Instead what I did, to fake it, was use the same image twice and fade out the opacity of the first image layer in Part 1. But if there's a better way I am certainly open to it.

 

My next challenge is to somehow animate the text within the pinned layers in Part2. 

 

Link to comment
Share on other sites

25 minutes ago, Rodrigo said:
var masterTimeline = new TimelineMax();
masterTimeline.add(part1()).add(part2(), "+=1");

masterTimeline.call(
  function () {
    //addClass, toggleClass, or your custom logic.
    $("#introBoxWrap").addClass("finished");
  },
  null,
  null,
  2
);

With this part I was just trying a few things, and never ended up using it but forgot to clean it out before posting.

Link to comment
Share on other sites

Hi,

 

4 minutes ago, vibe9 said:

But if there's a better way I am certainly open to it.

IMHO the codepen example I posted in my first post of the thread:

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

 

But if it's working for you then no need to fix it. As @mvaneijgen says: "If it works, it works" ;) 

5 minutes ago, vibe9 said:

My next challenge is to somehow animate the text within the pinned layers in Part2. 

Work on that and if you get stuck, just add a post in this thread or create a new one.

Happy Tweening!

Link to comment
Share on other sites

Yes, the old saying "if it ain't broke".

 

Well, I am not having much luck trying to animate text within the pinned layers.

 

I've been trying to combine my original circle animation timeline with another pinned layer example. But I can't seem to get the fading section timeline to "wait" for my circle animation to finish.  Any ideas would be very much welcome!

 

See the Pen yLxrdXw by vibe9 (@vibe9) on CodePen

Link to comment
Share on other sites

Hi,

 

Since you're using the same classes in all the elements and their children you can just create an array with the elements that you want to pin and then just select the fade child element you want to animate:

function part2() {
// Fade in backgrounds and then fade in text and pin it to the scroll
  gsap.set(".bgBox", { zIndex: (i, target, targets) => targets.length - i });

  const imageChange = gsap.timeline({ paused: true });

  imageChange
    .to("body", { opacity: 1, duration: 3.0 }, 0)
    .to(".bgBox.one", { opacity: 1, duration: 1.25, autoAlpha: 0 }, 1.0)
    .to(".bgBox.two", { opacity: 1, duration: 1.25 }, 1.0)
    .to(".bgBox.two", { opacity: 0, duration: 1.25 }, 2.0)
    .to(".bgBox.three", { opacity: 1, duration: 1.25 }, 2.0);

  ScrollTrigger.create({
    trigger: ".panelsContainer",
    start: "top top",
    end: "+=300%",
    pin: ".bgBox-wrap",
    animation: imageChange,
    scrub: true,
    markers: true
  });
  
  const pinElements = gsap.utils.toArray(".pin-me");  
  pinElements.forEach((pinEl) => {
    gsap.from(pinEl.querySelector(".fade-me"), {
      opacity: 0,
      scrollTrigger: {
        trigger: pinEl,
        start: "top center",
        end: "top top+=100",
        pin: true,
        scrub: true,
        markers: true,
      },
    });
  });
}

Here is a fork of your codepen:

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

 

Hopefully this helps.

Happy Tweening!

Link to comment
Share on other sites

4 hours ago, Rodrigo said:

Hi,

 

Since you're using the same classes in all the elements and their children you can just create an array with the elements that you want to pin and then just select the fade child element you want to animate:

function part2() {
// Fade in backgrounds and then fade in text and pin it to the scroll
  gsap.set(".bgBox", { zIndex: (i, target, targets) => targets.length - i });

  const imageChange = gsap.timeline({ paused: true });

  imageChange
    .to("body", { opacity: 1, duration: 3.0 }, 0)
    .to(".bgBox.one", { opacity: 1, duration: 1.25, autoAlpha: 0 }, 1.0)
    .to(".bgBox.two", { opacity: 1, duration: 1.25 }, 1.0)
    .to(".bgBox.two", { opacity: 0, duration: 1.25 }, 2.0)
    .to(".bgBox.three", { opacity: 1, duration: 1.25 }, 2.0);

  ScrollTrigger.create({
    trigger: ".panelsContainer",
    start: "top top",
    end: "+=300%",
    pin: ".bgBox-wrap",
    animation: imageChange,
    scrub: true,
    markers: true
  });
  
  const pinElements = gsap.utils.toArray(".pin-me");  
  pinElements.forEach((pinEl) => {
    gsap.from(pinEl.querySelector(".fade-me"), {
      opacity: 0,
      scrollTrigger: {
        trigger: pinEl,
        start: "top center",
        end: "top top+=100",
        pin: true,
        scrub: true,
        markers: true,
      },
    });
  });
}

Here is a fork of your codepen:

 

 

 

Hopefully this helps.

Happy Tweening!

 

 

That is perfect, thank you so much! I am learning a lot here. I really appreciate your help.

 

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