Jump to content
Search Community

GSAP Animation not working in Chrome Incognito or Safari

purple-lightsaber test
Moderator Tag

Recommended Posts

This is a Webflow site, so because there is a 10k character limit on svg code I have a workaround to fetch the SVG from a link. 

The async function animateSVG() is the one not working, but the footer SVG "async function animateFooterSVG()" is working on both Incognito Chrome and Safari. 


There is also a bug on each animation if you scroll down really fast, the hero SVG appears after fading out, and the footer SVG pops up without doing its draw in animation.

Any feedback is appreciated!

Website:
https://captivate-hr.webflow.io/

 

You can see the JS/ CSS code in Webflow by clicking the link below, hitting "P", clicking on the gear icon next to "Home", and scrolling down to the code:
https://preview.webflow.com/preview/captivate-hr?utm_medium=preview_link&utm_source=dashboard&utm_content=captivate-hr&preview=1cd5250b9c4cae29b70966c031419a96&workflow=preview

 

 

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/ScrollTrigger.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/ScrollToPlugin.min.js"></script>
 
<script>
// Configuration variables
const fadeInViewportOffset = 0.31; // Change this to control the viewport offset for fading in (0.5 = center)
const fadeOutViewportOffset = 0.67; // Change this to control the viewport offset for fading out (0 = top)
 
gsap.registerPlugin(ScrollTrigger);
 
// Animation setup
document.querySelectorAll(".scroll-component").forEach((scrollComponent) => {
  // Set the initial opacity to 0
  gsap.set(scrollComponent, { opacity: 0 });
 
  // Create a timeline for fade in and fade out animations
  const tl = gsap.timeline({
    scrollTrigger: {
      trigger: scrollComponent,
      start: "top bottom",
      end: "bottom top",
      scrub: true,
    },
  });
 
  // Fade in animation
  tl.to(
    scrollComponent,
    { opacity: 1, duration: 0.5, ease: "none" },
    `+=${fadeInViewportOffset}`
  );
 
  // Fade out animation
  tl.to(
    scrollComponent,
    { opacity: 0, duration: 0.5, ease: "none" },
    `+=${fadeOutViewportOffset}`
  );
});
 
(async function animateSVG() {
    const response = await fetch(
        'https://uploads-ssl.webflow.com/641aa8ecc04bba58c591560d/641d5fe1c09aba5648ed5232_home-wavelength.svg'
    );
    const svgContent = await response.text();
 
    const svgEmbed = document.getElementById('svg-embed');
    svgEmbed.innerHTML = svgContent;
 
    await new Promise((resolve) => {
        svgEmbed.querySelector('svg').addEventListener('load', () => {
            resolve();
        });
    });
 
    const NUM_PATHS = 40;
    const ANIMATED_PATHS_RANGE = [3, 7]; // range of paths to animate with scroll
    const speedFactor = 1;
    const svgSpeed = 0.64;
    const animationDuration = 1.65; // in seconds
 
    let lastScrollTop =
        window.pageYOffset || document.documentElement.scrollTop - 70;
    let paths = [];
 
    function setDashProperties(path) {
        const pathLength = path.getTotalLength();
        path.style.strokeDasharray = pathLength;
        path.style.strokeDashoffset = 0;
    }
 
    function initializePaths() {
        for (let i = 0; i < NUM_PATHS; i++) {
            const path = document.getElementById(`path${i}`);
            setDashProperties(path);
            paths.push(path);
        }
    }
 
    function animatePaths() {
        const paths = document.querySelectorAll('.hero-svg-path');
 
        paths.forEach((path, index) => {
            const pathLength = path.getTotalLength();
            path.style.strokeDashoffset = pathLength;
            gsap.to(path, {
                strokeDashoffset: 0,
                duration: animationDuration,
                ease: 'power1.inOut',
                onStart: () => {
                    path.style.strokeOpacity = 1; // set the stroke opacity to 1 when the animation starts
                },
            });
        });
    }
 
    function handleScroll() {
        const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
        const scrollHeight = document.body.scrollHeight - window.innerHeight;
        const scrollProgress = 1 - scrollTop / scrollHeight;
 
        const svg = document.getElementById('svg2');
        const horizontalMove = 0;
        const verticalMove = 0;
        const rotationSpeed = 0;
        const rotation = 0;
 
        gsap.to(svg, {
            x: horizontalMove,
            y: verticalMove,
            rotation: rotation,
            duration: 0.5,
        });
 
        const [animatedPathsStart, animatedPathsEnd] = ANIMATED_PATHS_RANGE;
        const animatedPaths = paths.slice(animatedPathsStart, animatedPathsEnd);
 
        animatedPaths.forEach((path) => {
            const pathLength = path.getTotalLength();
            const drawLength = pathLength * speedFactor * scrollProgress;
            const dashOffset = pathLength - drawLength;
            gsap.to(path, { strokeDashoffset: dashOffset, duration: 0.5 });
        });
 
        // Check if footer is in viewport
        const footer = document.querySelector('.footer');
        const footerRect = footer.getBoundingClientRect();
        const footerTopInView =
            footerRect.top >= 0 && footerRect.top < window.innerHeight;
        const footerBottomInView =
            footerRect.bottom > 0 && footerRect.bottom <= window.innerHeight;
 
        const heroSvgPaths = document.querySelectorAll('.hero-svg-path');
 
        if (footerTopInView || footerBottomInView) {
            // Footer is in viewport
            if (scrollTop > lastScrollTop) {
                // User is scrolling down
                heroSvgPaths.forEach((path) => {
                    gsap.to(path, { strokeOpacity: 0, duration: 0.5 });
                });
            }
        } else {
            // Footer is not in viewport
            if (scrollTop < lastScrollTop) {
                // User is scrolling up
                heroSvgPaths.forEach((path) => {
                    gsap.to(path, { strokeOpacity: 1, duration: 1.8 });
                });
            }
        }
 
        lastScrollTop = scrollTop;
    }
 
    function handleFooterIntersection(entries, observer) {
        entries.forEach((entry) => {
            if (entry.isIntersecting) {
                // Footer is in view
                const heroSvgPaths = document.querySelectorAll('.hero-svg-path');
                heroSvgPaths.forEach((path) => {
                    gsap.to(path, { strokeOpacity: 0, duration: 0.5 });
                });
            } else {
                // Footer is out of view
                const heroSvgPaths = document.querySelectorAll('.hero-svg-path');
                heroSvgPaths.forEach((path) => {
                    gsap.to(path, { strokeOpacity: 1, duration: 1.8 });
                });
            }
        });
    }
 
    function initializeAnimation() {
        initializePaths();
        animatePaths();
 
        // Set up the Intersection Observer to monitor the footer
        const observer = new IntersectionObserver(handleFooterIntersection);
        const footer = document.querySelector('.footer');
        observer.observe(footer);
 
        // Add a scroll listener to handle the SVG path animations on scroll
        window.addEventListener('scroll', handleScroll);
    }
 
    document.addEventListener('DOMContentLoaded', initializeAnimation);
    window.addEventListener('load', initializeAnimation);
})();
 
function initializeAnimation() {
  (async function animateFooterSVG() {
    const response = await fetch(
      'https://uploads-ssl.webflow.com/641aa8ecc04bba58c591560d/641e919471c8e50f896a65a6_footer-wavelength.svg'
    );
    const svgContent = await response.text();
 
    const svgEmbed = document.getElementById('footer-svg-embed');
    svgEmbed.innerHTML = svgContent;
 
    const NUM_PATHS = 37;
    const animationDuration = 2.0; // in seconds
    const drawInDuration = 2.0; // in seconds, controls the speed of the animation
    let paths = [];
 
    function setDashProperties(path) {
      const pathLength = path.getTotalLength();
      path.style.strokeDasharray = pathLength;
      path.style.strokeDashoffset = pathLength;
      path.style.strokeOpacity = 0;
    }
 
    function initializePaths() {
      const footerSvgPaths = document.querySelectorAll('.footer-svg-path');
      for (let i = 0; i < footerSvgPaths.length; i++) {
        const path = footerSvgPaths[i];
        setDashProperties(path);
        paths.push(path);
      }
    }
 
    function handleFooterIntersection(entries, observer) {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          // Footer is in viewport
          paths.forEach((path) => {
            const pathLength = path.getTotalLength();
            gsap.to(path, {
              strokeDashoffset: 0,
              duration: drawInDuration,
              ease: 'power1.inOut',
              onStart: () => {
                path.style.strokeOpacity = 1;
              },
            });
          });
        } else {
          // Footer is not in viewport
          paths.forEach((path) => {
            const pathLength = path.getTotalLength();
            gsap.to(path, {
              strokeDashoffset: pathLength,
              duration: 0.5,
              onComplete: () => {
                path.style.strokeOpacity = 0;
              },
            });
          });
        }
      });
    }
 
    initializePaths();
 
    const observer = new IntersectionObserver(handleFooterIntersection);
    const footer = document.querySelector('.footer');
    observer.observe(footer);
  })();
}
 
document.addEventListener('DOMContentLoaded', initializeAnimation);
window.addEventListener('load', initializeAnimation);
 
</script>
Link to comment
Share on other sites

Hi,

 

Are you completely sure that the animateSVG function is being executed? It seems that you're trying to create an IIFE it seems that it doesn't execute. You could follow the same path you're doing in your other block and just create a function and call that function that holds the async blocks. Since that particular approach is working, perhaps replicate it in the other section as well.

 

Also it's a curious thing that you have this:

document.addEventListener('DOMContentLoaded', initializeAnimation);
window.addEventListener('load', initializeAnimation);

Why are you calling that twice? Why not the load event and be done with it?

 

Hopefully this helps.

Happy Tweening!

Link to comment
Share on other sites

@Rodrigo thanks for the input, I've tried copying what the other block is doing but it seems to break it completely. The code does execute in normal Chrome, but yes for some reason it doesn't seem to fire in Safari or incognito. 

 

Also I was calling it twice to ensure it fires and hard refreshes, since that was giving me issues as well. I will try removing one though. 

 

Thank you

Link to comment
Share on other sites

Hi,

 

Unfortunately the Webflow page is read only so I can't really do anything there to test stuff like console calls or anything of the sort, that's why we normally ask for Codepen examples as a minimal demo, which allows us to test and see what could be the issue.

 

 I know this sucks but if I was you I'd start in the simplest possible way, that is comment out all the GSAP code and focus on the async part of your code working as expected, then move onto adding GSAP to the mix.

 

If you get stuck along the way and have a specific GSAP related issue, be sure to let us know and include a minimal demo.

 

Sorry I can't be of more assistance.

Happy Tweening!

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