Jump to content
Search Community

Asored

Business
  • Posts

    23
  • Joined

  • Last visited

Posts posted by Asored

  1. Hey everyone!

     

    First of all, and sorry for the Offtopic: this new gsap website is just amazing. Great work!

     

    Now about the problem I'm currently fighting with. I've created a minimal demo to understandable reproduce the issue.

     

    Demo description in short: When new items with the same class are coming to the DOM, only the old ones are animated.

     

    Detailled version:

     

    When a timeline is created, targets are saved, which are DOM nodes in the end. If I've researched this correctly, the function uses `querySelectorAll()`. That's good so far, but I'm currently encountering a problem.

     

    I have a context where data is dynamically loaded on a page (a facet filter system, where different data are pulled from the server but always have the same class). I want to animate the reloading of these contents by restarting the GSAP timeline with .restart() after the server request. Unfortunately, the timeline does not recognize the new elements, which is understandable up to this point, as it only saved those that were in the DOM at the time the timeline was created.

     

    My question: is it somehow possible to update the timeline instance so that it also includes the new elements present in the DOM?

     

    Of course, the sensible approach here would be to simply create a new timeline. However, in my case, this is not possible because it's a UI platform where users create the timeline that they can restart in different situations. So, it's a prerequisite that the same timeline is used. Is this somehow possible?

     

    I would be very grateful for any help!
     

    See the Pen qBvBddL by asored (@asored) on CodePen

  2. Hi! I try to understand an issue which currently occurs for a pinned animation in combination with SplitText and display: flex parent containers.

     

    As you can see in the pen, SplitText seems not to render this string correctly when the text element (in this case h1) has a parent element with display: flex (in this case .container). It splits the text into two lines.

     

    Changing the parent to display: block, the rendering is fine and the headline remains one line. This would be the expected (or desired) behavior. This error only appears while the PIN functionality is activated.

     

    Is there a common way to handle with such situations?

    See the Pen dyqbmrj by asored (@asored) on CodePen

  3. Hi all! :)

     

    I understand the principal logic of immediateRender. Setting this value to true may be definitely needed for .from and .fromTo methods, where we need the initial properties very fast. But I'm on a situation where I need to set immediateRender to false. As you can see in the Codepen, some basic staggered splittext animations are not working as I expect. Seems that the animation starts without setting the initial properties for each char element.

     

    Is there a way to force gsap to wait for the initial value while setting immediateRender to false? By the way, I need this for a backend UI where the user can change the progress of a timeline with a dragger. Also wenn the .progress is setting manually to position 0, the element never gets the initial properties. You can see this example in my pen in the setTimeout function, where I set the timeline to the position 0 after three seconds.

     

    I really appreciate your help!

    See the Pen qByeQrV by asored (@asored) on CodePen

  4. Hi there! First of all, sorry for always coming up with such tricky questions here. ;-)

     

    In my application, the user can create timelines via a UI. I store all created timelines in a variable and can access them later to play them as needed.

    Now I had the case that every item of a navigation should be animated on mouseenter. Here it became a challenge for me to find the right timeline for the right item.

     

    I added comments to my codepen code and I tried to create my project as simple as possible minimized. 

     

    Simply asked, do I have the ability to get a reference in the timeline object to the elements it will animate? If so, I could just query that.

     

    Or is there a better solution for my use case?

    See the Pen VwdpNvq by asored (@asored) on CodePen

  5. Hi there!

     

    I'm trying to create some very basic timelines which I can use on different places on the website / page, adding a class to an element. 

    For example: Each element with the class .animate-me should animate y: -100 when entering the viewport.

     

    I have a problem with the scrollTrigger start and end values. When checking my attached CodePen, you will see that the animation for all .animation2 elements is triggering when the first element with the class .animation hits the center of the viewport. I think that is the expected behavior.

     

    But how could I make the trigger relative to the element which enters the viewport? In the CodePen, the second headline "Another headline" should start to animate when the second a.animation hits the center of the viewport. 

     

    When iterating the triggers, I could choose the trigger selector to animate exactly this element. This works (.animation) But what if I want to animate other selectors in this timeline? (.animation2 in my example) Is there a best practice to handle such situations? 

     

    I hope that I could describe my problem understandable. If not, please ask me :)

     

    See the Pen ExRNawq by asored (@asored) on CodePen

  6. 22 hours ago, Carl said:

    Thanks for the clear demo. Things are working as designed. Changing the duration of a tween after it is inserted into a timeline does not shift every animation after it. This is done mainly as a performance optimization as it would be quite taxing for every animation to constantly be aware of changes to its duration. 

     

    However, you can use shiftChildren()

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

     

    demo

     

     

    Hi @Carl Thanks so much! Works like a charm! :)

     

     

     

     

  7. Hi everyone!

     

    I have a question which is very simple to ask, but where I currently do not know what to do. 

     

    To make it clear, I've created a codepen on which I tried to reproduce my project as simple as possible. Basically, if I change a tween within a timeline, how do I make all the other tweens change with it? For example I could update the duration of a tween..and depending on the duration for a tween, the next tween in the timeline should change the startTime. Or do I understand something wrong? 

     

    If my timeline has two tweens, both with the duration of 1 second. The structure will look like that:

     

    First Tween: Duration: 1, Start Time: 0

    Second Tween: Duration: 1, Start Time: 1

     

    When changing now the duration for the first tween to 5, for my understanding it should be:

     

    First Tween: Duration: 5, Start Time: 0

    Second Tween: Duration: 1, Start Time: 5

     

    But the start time remains to: 1. Please check my CodePen example. There you'll find some comments about this.

     

    The context is that I'm creating a timeline visualization. I need to change the values in real time. The UI is located in a different place than where the timeline creation is located. Therefore I have to work with a parent variable that stores the timelines globally. I think that should be fine. The user can change the duration of each tween inside an Input field. As result, the duration of the timeline changes successfully. But all other tweens ignores the change of this one tween.

     

    Do you have an idea how to achieve what I need? I hope that I was able to explain this understandably enough. :-)

     

     

    See the Pen rNKxxVe by asored (@asored) on CodePen

  8. 8 hours ago, GreenSock said:

    I don't mind updating MotionPathHelper to FORCE the path color, width, and opacity according to what you define. Is that what you're requesting? 

     

    Hi @GreenSock, understood. Thanks for the clarification! And yes, I think that would be the expected behavior – at least at the first thought. I think that would really make sense, also regarding the `start` and `end` arguments. Lets say the user defines a very small path. It is almost impossible to grab the end of the path to change it afterwards, because the animation is looping around the path. As workaround he can increase the duration to have the chance to grab the path dot. As solution we could just say: `end: 0.8` and as result, the end of the path will always be free for mouse interactions. Just to talk about a possible use case.

     

    Is there a workaround for me to force the arguments to have an effect – also for existing paths?

    • Like 1
  9. 15 hours ago, GreenSock said:

    I'm not seeing anything broken - can you please provide a minimal demo that shows the problem very clearly? The one you provided appears to work correctly but maybe I'm missing something. 

     

    Hi GreenSock! I've simplified the example removing the astronaut :-)

     

    But in general I talk about the following lines:

    MotionPathHelper.create(".astronaut", {
      path: "#path",
      pathWidth: 5,
      pathColor: "red",
      pathOpacity: 0.6,
      selected: true,
      start: 0.1,
      end: 0.5,
      duration: 5,
      ease: "power2.inOut"
    });

    The documentation says: `You can optionally pass in a vars parameter to further configure the motion path helper. It's an object and can include any of the following properties:`. I've used the properties above and expect the following:

     

    - The width of the displayed path should be 5

    - The path color should be not blue, but red

    - The path opacity should be 0.6

    - The object should end on the half of the path

    - ..... and so on

     

    But all passed arguments seem to not have an affect. Just the basic blue path appears.

     

    Do I missunderstand something here? Are the arguments perhaps doing something different than I understand?

  10. @GreenSock @mvaneijgen Thanks so much for your feedback! I've got it to work calculating the viewBox dynamically depending on the path:

     

    // Calculate Viewbox
    let clientRect = document.querySelector(pathElementClass).getBBox();
    let viewBox = clientRect.x+' '+clientRect.y+' '+clientRect.width+' '+clientRect.height;
    document.querySelector(pathElementClass).closest('svg').setAttribute('viewBox', viewBox);

    It works like a charm. GreenSock, great concept to recalculate also the motion values. But I think this will be too much. Its okay for me to have the new calculated viewBox on page reload. If I need this at some point, I will return to this post. ;-) 

    • Like 1
  11. Hi! As the documentation says, we can pass arguments to the `MotionPathHelper.create()` function. But all arguments are getting ignored for some reason. I've tried it also in your official example from the documentation page. Are there any breaking changes in the new MotionPathHelper version that require me to pass the arguments differently than what the documentation says?

    See the Pen yLjpEwW by asored (@asored) on CodePen

  12. 9 hours ago, GreenSock said:

    I'm sticking with my theory. 

     

    If I were you, I'd put a console.log() right before the tween to see if your setup code is running multiple times and if the rotationX values are what you THINK they are. I bet they're not. 

     

    You could solve it by using .fromTo() tweens, but that's sort of masking over the real problem. You definitely don't want to be adding multiple event listeners to the same elements and trying to run multiple duplicate animations simultaneously. By the way, I think you want "mouseenter", not "mouseover" (the latter may fire multiple times when you're over the same element - each descendant). 

     

    Hi GreenSock! Thanks for your feedback! Good hint with the `mouseenter`. I've completely overseen this.

     

    As you recommended, I've included some console.log() to my code to be sure that the code only runs once. Its important in this case that we have to separate the frontend output from the broken backend output where to code does not work as expected.

     

    Console – Frontend Output

    Creating timeline
    Set timeline settings
    Create Timeline animations
    Wait for event trigger
    Mouseenter event triggered
    Mouseleave event triggered
    Mouseenter event triggered
    Mouseleave event triggered

    Here everything seems to be okay, the way I would judge it.

     

    Console – Backend (where the DOM is loaded twice)

    JQMIGRATE: Migrate is installed, version 3.3.2
    JQMIGRATE: Migrate is installed, version 3.3.2
    Creating timeline
    Set timeline settings
    Create Timeline animations
    Wait for event trigger
    Creating timeline
    Set timeline settings
    Create Timeline animations
    Wait for event trigger
    Creating timeline
    Set timeline settings
    Create Timeline animations
    Wait for event trigger
    (3) Mouseenter event triggered
    (3) Mouseleave event triggered

    As you can see, in this case the DOM is rendered not twice, but three times! I hope they will fix the bug soon. But for now, I have to find a workaround for my application. 🤔 By the way: man thanks to you and your great community. This forum is just an enrichment! 👏

     

    --EDIT--

    I've found a temporary workaround by saving the timeline into a variable and checking if is active or not:

    flip.addEventListener("mouseleave", event => {
      if (tl.isActive()) {
        return;
      }
      tl.reverse();
    });

    May really not be the best solution, but I think in this case I can play with the weird DOM loading.

  13. I'm just playing with the incredible MotionPath plugin. The MotionPathHelper extension is very helpful for my users to build easily custom paths without struggling in Illustrator. But I already know. There will come questions like: "Why this is not responsive? We cannot use this in production if so". Is there a way to make such a scenario responsive and limit it to the viewport?

     

     

    I don't think if we can play with nested SVG and if its a best practice to do so, but what if the user want to create a MotionPath from another element type like an image? In general I don't know what I get. The user can choose any HTML code and create paths for it.

     

    Have any of you thought about this specifically, how to solve something like this?

    See the Pen jOxadKJ by asored (@asored) on CodePen

  14. 46 minutes ago, Cassie said:

    Hey there!

     

    It's not so much 'best practice'. If you're planning on creating a timeline with multiple animations on it, and you're adding the animations by looping around, the timeline will need to be defined outside the loop - otherwise you'll just be creating multiple timelines every time you loop with one animation on each. But maybe you're aiming for that here? Hard to tell exactly as I don't know what the end aesthetic result is you're going for without seeing a demo.

     

    FYI - Minimal demos don't have to exactly represent your live example. In fact it's better if they're simplified down as much as possible, just some coloured boxes and minimal styling. See if you can recreate the issue with as few dependancies as possible. If not, incrementally add code bit by bit until it breaks. Usually people solve their own issues during this process! If not, then at least we have a reduced test case which greatly increases your chances of getting a relevant answer.

    It's very hard (near impossible) for us to troubleshoot an issue just by looking at some isolated GSAP code.

     

    Here's a starter CodePen that loads all the plugins. A minimal demo would be hugely helpful 

     

     

    Hey Cassie! Thanks very much! You're right. I've created a codepen with my code and simplified it removing the switch case blocks to focus on the relevant parts. In general this is what I try to do. A very simple flip box. As you can see, the code works. Also in my WordPress environment in frontend. But exactly the same code does not work correctly in backend when viewing trough the builder which loads it as iframe. The reverse finishes not on 100%, but pauses on 80-90%. Because of a current bug, the builder loads the DOM twice. I thought that this causes the error, because with a workaround for the builder which loads the DOM once, the animation works again, also in the builder.

     

    What do you think?

     

    See the Pen bGMYaVw by asored (@asored) on CodePen

  15. 35 minutes ago, GreenSock said:

    I've never heard of the DOMContentLoaded event firing twice, and I'm confident that has nothing to do with GSAP. 

     

    No, it doesn't matter if you called .reverse() on the animation a bunch of times while it's running - it would just continue going in that direction. It's sorta like saying "go in the backwards direction", and if it's already going in that direction it doesn't really do anything different - it just ensures that the playhead is going in that direction. Here's proof: 

     

     

     

    That calls reverse() every 500ms on that tween. Notice it makes no difference at all - it just keeps going and is not interrupted.

     

    I would not add the .isTweening() condition in there. I'm concerned you've got some other fundamental problem going on in your code, and that condition may just sorta cover up the real problem (I actually doubt it'll have any effect whatsoever). 

     

    My suspicion is that you are actually creating multiple conflicting tweens. And the first one has already started moving the element when the second one starts, thus that "starting" value is affected. So it's likely a logic problem in your code. A minimal demo is essential in troubleshooting. 

     

    Thanks so much for your words! And also you, Rodrigo! Awesome people here in the forum! :)

     

    Regarding the problem I have, I badly cannot provide a codepen demo, because this plays inside a WordPress installation with a Page Builder. The Page Builder itself currently has a bug which loads the DOM content twice. (iframe). In the frontend view, where the DOM content is loading once, the reverse animation works well. But in the backend (builder) view, where the DOM is loaded twice, I get this strange behavior. As workaround I tried to force the javascript function where the animation was created only to load on the first DOM load..and yea, the reverse works then also in the builder view. This shows me: it really has anything to do with the double DOM loading. Very strange.

     

    I'll post the code from my javascript function. Maybe this helps. By the way. I see its a good practice to create the timeline outside of the for loop. In this case its not possible because I need to integrate date from the looped items. Or do you have a better idea?

     

    Here the code:

     

    async function gsapExample() {
    
      gsap.utils.toArray('.elem-flip-wrapper').forEach(flip => {
          
          let wrapper = flip;
          let box = wrapper.querySelector(".elem-flip-box");
          let front = wrapper.querySelector('.elem-flip-front');
          let back = wrapper.querySelector('.elem-flip-back');
    
          let animationType = flip.getAttribute('data-type');
          let duration = flip.getAttribute('data-duration');
          let delay = flip.getAttribute('data-delay');
          let trigger = flip.getAttribute('data-trigger');
          let onComplete = flip.getAttribute('data-oncomplete');
          let onStart = flip.getAttribute('data-onstart');
          let onReverseComplete = flip.getAttribute('data-onreversecomplete');
    
          animationType = animationType ? animationType : 'flip';
          duration = duration ? duration : 1;
          delay = delay ? delay : 0;
          trigger = trigger ? trigger : 'hover';
          onComplete = onComplete ? new Function (onComplete) : '';
          onStart = onStart ? new Function (onStart) : '';
          onReverseComplete = onReverseComplete ? new Function (onReverseComplete) : '';
    
          const tl = gsap.timeline({ paused: true,
            onStart: function() {
              typeof onStart == 'function' ? onStart() : '';
            },
            onComplete: function() {
                typeof onComplete == 'function' ? onComplete() : '';
            },
            onReverseComplete: function() {
                typeof onReverseComplete == 'function' ? onReverseComplete() : '';
            }
          });
    
          gsap.set(wrapper, {
              transformStyle: "preserve-3d",
              transformPerspective: 1000
          });
          gsap.set(box, {
              transformStyle: "preserve-3d",
              transformOrigin: "50% 50%",
          });
          gsap.set(back, {
              rotationY: 180, rotationZ: 180
          });
    
          switch (animationType) {
              case 'flip':
                  tl.to(front, { rotationX: 180, duration: duration }, delay);
                  tl.to(back, { rotationX: 180, duration: duration }, delay);
                  break;
              case 'fade':
                  gsap.set(back, { rotationX: 180 });
                  tl.to(front, { opacity: 0, duration: duration }, delay);
                  tl.to(back, { opacity: 1, duration: duration }, delay);
                  break;
              case 'fadeShrink':
                  wrapper.style.overflow = 'hidden';
                  gsap.set(back, { rotationX: 180 });
                  tl.to(front, { scale: .8, opacity: 0, duration: duration/2 }, delay);
                  tl.to(back, { opacity: 1, duration: duration }, delay);
                  break;
              case 'fadeUp':
                  wrapper.style.overflow = 'hidden';
                  gsap.set(back, { rotationX: 180, translateY: 500, opacity: 0 });
                  tl.to(front, { opacity: 1, rotationX: 180, duration: duration }, delay);
                  tl.to(back, { translateY: 0, opacity: 1, duration: duration }, delay);
                  break;
              case 'overlay':
                  wrapper.style.overflow = 'hidden';
                  gsap.set(back, { rotationX: 180, translateY: 500, zIndex: 1 });
                  tl.to(back, { translateY: 0, duration: duration }, delay);
                  break;
              case 'overlayShrink':
                  wrapper.style.overflow = 'hidden';
                  gsap.set(back, { rotationX: 180, translateY: 500, zIndex: 1, scale: .9 });
                  tl.to(back, { translateY: 0, duration: duration }, delay);
                  break;
              default:
                  break;
          }
    
          switch (trigger) {
              case 'hover':
                  flip.addEventListener("mouseover", event => {
                      tl.play();
                  });
                  flip.addEventListener("mouseleave", event => {
                      tl.reverse();
                  });
                  break;
              case 'click':
                  flip.addEventListener("click", event => {
                      if (flip.classList.contains('active')) {
                          tl.reverse();
                          flip.classList.remove('active');
                      } else {
                          flip.classList.add('active');
                          tl.play();
                      }
                  });
              default:
                  break;
          }
      })
    }

     

  16. I refer to the following post: 

    In order to keep the forum clear, I created a new thread because the last question of the thread is about a different issue. That way others looking for it can find the solution faster.

     

    The issue is the following: In the environment I need to integrate a gsap animation currently is a small bug. The DomContentLoaded eventListener fires twice. I can't change this behavior and I need to play with it.

     

    This seems to be a problem for the tl.reverse(). The reverse animation stops until finishing. To make it more clear: I animate a translateX from 180 to 0..and the reverse() stops for example on 15. I think this is because there is triggered a second reverse() until the first is finished. Is there a way to say: "Hey! Please ignore other requests and animate only once"? Something like a force function to definitely finish the reverse animation.

     

    Or how could I handle a such scenario?

     

  17. 26 minutes ago, Rodrigo said:

    Hi @Asored,

     

    The main issue seems to be that the back face is rotating as well inside the wrapper. In this cases I feel that is always better to rotate both faces instead of the container. This setup seems to work IMHO:

    gsap.utils.toArray('.inner').forEach(flip => {
        
      let wrapper = flip;
      let box = wrapper.querySelector(".box");
      let front = wrapper.querySelector('.front');
      let back = wrapper.querySelector('.back');
    
      gsap.set(wrapper, {
        transformStyle: "preserve-3d",
        transformPerspective: 1000
      });
      gsap.set(back, {
        rotationX: -180
      });
    
      const timing = 1;
    
      const tl = gsap.timeline({ paused: true })
      .to(wrapper, { scale: 1, duration: timing }, 0)
      .to(front, { rotationX: 180, duration: timing }, 0.5)
      .to(back, { rotationX: 0, duration: timing }, 0.5)
      .to(wrapper, { z: 50, duration: timing/2, yoyo: true, repeat: 1 }, 0);
    
      flip.addEventListener("mouseover", event => {
        tl.play();
      });
      flip.addEventListener("mouseleave", event => {
        tl.reverse();
      });
    })

    Hopefully this works as you expect. Let us know if there's any other question regarding GSAP.

     

    Happy Tweening!!!

     

    Great, thanks very mich, Rodrigo! I really appreciate your help. It works well animating only the children.

    There is just another issue. In the system I need to integrate this animation currently is a small bug. The DomContentLoaded eventListener fires three times. I can't change this behavior and I need to play with it.

     

    Firering the page three times seems to be a problem for the tl.reverse(). The reverse animation stops until finishing. Is there a way to say: "Hey! Please ignore other requests and animate only once"?

  18. Hi guys! I'm really in love with Gsap and want to use it for my future projects. I'm sure I'll join the Business Membership. Awesome work.

    Since I'm still in the getting-to-know phase, I may have a question that I'm sure seems obvious to you.

     

    I try to animate a typical Flip Card with a gsap timeline. Works like a charm! But: When more then one elements / cards are on the page and I create a loop (in my case with the gsap util toArray.forEach), the animation seems to be broken. No error messages in the console, each element can be found by gsap. So I don't know where is the problem here. For some reason the back of the card is going to be white.

     

    When realizing that without foreach and directly with one element, everything works. What's the error here? Did I misunderstood some important concepts? Wish you a great weekend!

     

    See the Pen NWMaZXG?editors=0110 by asored (@asored) on CodePen

  19. Hi :) I'm new with GSAP and I like it very much! Thanks for your great work!

     

    Just a beginner question: I try to animate the following simple thing:

    https://codepen.io/Asored/pen/PoGYyOg

     

    In my project I trigger the window scroll position instead of waiting for a click event. How could I create the animation from current relative position to a fixed position on bottom right? 

     

    This is my try:

    ScrollTrigger.create({
      start: 'top 20%',
      trigger: '#contact--btn',
      markers: false,
      scrub: true,
      onEnter: () => {
        var windowWidth = $(window).width();
        var windowHeight = $(window).height();
        var buttonWidth = $("#contact--btn").width();
        var buttonHeight = $("#contact--btn").height();
        var buttonOffsetLeft = $('#contact--btn').offset().left;
        var buttonOffsetTop = $('#contact--btn').offset().left;
        
        gsap.to('#contact--btn', {
          x: (windowWidth - buttonOffsetLeft) - buttonWidth - 250,
          y: (windowHeight - buttonOffsetTop) - buttonHeight - 250
        })
    
        setTimeout(function () {
          $("#contact--btn").css("position", "fixed");
        }, 10)
      },
    })

    This is not really elegant. Also the animation is not smooth because of the small break from the setTimeout function.

    Is there a better way to create animations like this with GSAP?

     

    Thanks in advance for your help! :)

     

    Best regards

    See the Pen PoGYyOg by Asored (@Asored) on CodePen

×
×
  • Create New...