Jump to content
Search Community

.kill() does not work

Enrypase test
Moderator Tag

Recommended Posts

Hi everybody,

I have the following problem: it seems like I can't kill the animations.
I have this animation:
 

gsap.to(thisEl, {left: maxLeft, duration: props.duration, ease: Linear.easeNone, repeat: -1, delay: props.delay})

Googling I found out that I can't update the variables once the animation is started.
So i thouht that a good idea was to delete/kill the animation and starting a new one with the updated value.
The code is the following:

	// Maxiumum left attribute that the cloud must reach & animation
    let maxLeft, animation
    
    // This funcion is executed on window resize (evt != null) and for the first time the program is executed (evt === undefined)
    function updateWindow(evt){
        // If it is the first execution update the left parameter and set currentHeight & currentWidth
        if(!evt){
            thisEl = $(`#${props.propId}`)
            thisEl.css("left", -2 * thisEl.width())
        }
      	// Updating the variable
        maxLeft = 2 * thisEl.width() + $(window).width()
      	// If the resize event occurs, delete the animation and start a new one
        if(evt){
            animation.kill()
            animation = gsap.to(thisEl, {left: maxLeft, duration: props.duration, ease: Linear.easeNone, repeat: -1, delay: props.delay})
        }
      // If this is the first execution start the first animation
      else{
            animation = gsap.to(thisEl, {left: maxLeft, duration: props.duration, ease: Linear.easeNone, repeat: -1, delay: props.delay})
        }
    }
    function stopAnimation(){
        animation.kill()
    }
	/* Other code... */
	<button onClick={stopAnimation}>CLICK</button>

So, it seems like the animation.kill() inside updateWindow() does not work.
And the animation.kill() that is executed when the button is clicked does not work either. (The animation still being executed)

 

Thanks in advance :D

Link to comment
Share on other sites

Hey there, welcome to the forums!

 

I don't see a reason why you couldn't kill a tween - as long as you can access that variable from whichever scope you happen to be in.

Let's step back to this comment first though - What was your original goal with this? Maybe we can suggest a better route to get there.

Quote

Googling I found out that I can't update the variables once the animation is started.

 

  • Like 2
Link to comment
Share on other sites

54 minutes ago, iDad5 said:

It seem to me, that you have a scoping issue. I cannot see where you create your first animation, so please provide us with a codePen or at least more of the code that's in play.

I create my first animation in of updateWindow()

else{
            animation = gsap.to(thisEl, {left: maxLeft, duration: props.duration, ease: Linear.easeNone, repeat: -1, delay: props.delay})
}

This is just a piece of all the code.
I'll try right now to provide a codePen :D

 

[EDIT:]

In the meanwhile I'll share all the component code down here, maybe it helps...
 

import React, {useEffect, useContext} from "react"
import {gsap, Linear} from "gsap"
import $ from "jquery"
import "../style/backgroundCloud.css"

function BackgroundCloud(props){
    // Current element
    let thisEl
    // Refreshes the component
    let isLoaded = useContext(props.pageLoaded)
    // Maxiumum left attribute that the cloud must reach & animation
    let maxLeft, animation
    
    function updateWindow(evt){
        // If it is the first execution update the left parameter and set currentHeight & currentWidth
        if(!evt){
            thisEl = $(`#${props.propId}`)
            thisEl.css("left", -2 * thisEl.width())
        }
        // --> This code must be executed in both vertical and horizontal resize <--
        maxLeft = 2 * thisEl.width() + $(window).width()
        // Adapting cloud to new top
        const parent = thisEl.parent().parent().parent()
        const fromTop = parent.offset().top
        const parentDistance = fromTop + parent.height() / 2
        let top = props.top
        if(top.includes("vh")){
            top = top.replace("vh", "")
            top = top * 0.01
            top = $(window).height() * top
        }else if(top.includes("px")){
            top = top.replace("px", "")
        }
        thisEl.css("--top", String(parentDistance + top).concat("px"))
        if(evt){
            animation.kill()
            animation = gsap.to(thisEl, {left: maxLeft, duration: props.duration, ease: Linear.easeNone, repeat: -1, delay: props.delay})
        }else{
            animation = gsap.to(thisEl, {left: maxLeft, duration: props.duration, ease: Linear.easeNone, repeat: -1, delay: props.delay})
        }
    }
    // Exec when the site is loaded/the component refreshed
    useEffect(() => {
        if(isLoaded){
            updateWindow()
            $(window).off().on("resize", updateWindow)
        }
    }, [])


    function killComponent(){
        
        if(animation){
            animation.kill()
        }  
    }

    // Return default cloud
    return(
        <div className="backgroundCloudContainer">
            <img src={props.background} className="backgroundCloud" id={props.propId} draggable="false" alt={props.propId}
            style={{
                "--z-index": props.zIndex,
                "--top": props.top,
                "--scale": props.scale
            }}/>
            <button onClick={killComponent}>CLICK</button>
        </div>

        
    )
}
export default BackgroundCloud

I'm trying to replicate the same situation in JS but everything works fine.
So, maybe, the problem is with React

Link to comment
Share on other sites

8 minutes ago, Cassie said:

Hey there, welcome to the forums!

 

I don't see a reason why you couldn't kill a tween - as long as you can access that variable from whichever scope you happen to be in.

Let's step back to this comment first though - What was your original goal with this? Maybe we can suggest a better route to get there.

 

My goal is to update an animation on a window resize event :D
So I thought the easiest way was to delete the animation with .kill() and to create a new one with the updated variable

Link to comment
Share on other sites

 

Agree with logging out 'animation' - but also, Just going on some of the code in the screengrab it'll be helpful to give our React guide a little run through.

 

React doesn't play too nicely with DOM scripting, so it's recommended to use refs instead of grabbing elements directly. Using jQuery and React together is quite a bold choice too. They're both quite opinionated and have conflicting methodologies

 

Link to comment
Share on other sites

10 minutes ago, Cassie said:

React doesn't play too nicely with DOM scripting, so it's recommended to use refs instead of grabbing elements directly. Using jQuery and React together is quite a bold choice too. They're both quite opinionated and have conflicting methodologies

Sounds very much like that old couple across the street 

 

happy-anniversary-cane.gif

  • Haha 2
Link to comment
Share on other sites

Before trying those things together, I noticed that React calls multiple times my function, so, is enabling overwriting a good way for "skipping" some problems? And is 

gsap.defaults({overwrite: "auto"});

a good way for enabling it?
(From:

)

  • Like 1
Link to comment
Share on other sites

It's pretty tough to troubleshoot without a minimal demo - the issue could be caused by CSS, markup, a third party library, your browser, an external script that's totally unrelated to GSAP, etc. Would you please provide a very simple CodePen or CodeSandbox that demonstrates the issue? 

 

Please don't include your whole project. Just some colored <div> elements and the GSAP code is best (avoid frameworks if possible). 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.

 

Here's a React template.

 

Once we see an isolated demo, we'll do our best to jump in and help with your GSAP-specific questions.  Setting overwrite to "auto" or true can be good, but it's important that you understand what's going on and what that's solving so that you can ensure it's not just a band-aid that covers over something like creating a bunch of conflicting animations unnecessarily.

  • Like 1
Link to comment
Share on other sites

3 minutes ago, GSAP Helper said:

It's pretty tough to troubleshoot without a minimal demo - the issue could be caused by CSS, markup, a third party library, your browser, an external script that's totally unrelated to GSAP, etc. Would you please provide a very simple CodePen or CodeSandbox that demonstrates the issue? 

 

Please don't include your whole project. Just some colored <div> elements and the GSAP code is best (avoid frameworks if possible). 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.

 

Here's a React template.

 

Once we see an isolated demo, we'll do our best to jump in and help with your GSAP-specific questions.  Setting overwrite to "auto" or true can be good, but it's important that you understand what's going on and what that's solving so that you can ensure it's not just a band-aid that covers over something like creating a bunch of conflicting animations unnecessarily.

I did not include a demo because it worked perfectly in that...
Anyways, I figured out the problem, and was *not* about gsap.
Would be helpful to describe it and write the solution even if was because external to gsap?

  • Like 2
Link to comment
Share on other sites

I'm posting the final code down here:
 

function BackgroundCloud(props){
    // Current element
    let thisEl
    // Refreshes the component
    let isLoaded = useContext(props.pageLoaded)
    // Maxiumum left attribute that the cloud must reach & animation
    const maxLeft = useRef(0)
    const animation = useRef([])
    
    function updateWindow(evt){
        // If it is the first execution update the left parameter and set currentHeight & currentWidth
        if(!evt){
            resetComponent()
        }
        // --> This code must be executed in both vertical and horizontal resize <--
        maxLeft.current = 2 * thisEl.width() + $(window).width()
        // Adapting cloud to new top
        const parent = thisEl.parent().parent().parent()
        const fromTop = parent.offset().top
        const parentDistance = fromTop + parent.height() / 2
        let top = props.top
        if(top.includes("vh")){
            top = top.replace("vh", "")
            top = top * 0.01
            top = $(window).height() * top
        }else if(top.includes("px")){
            top = top.replace("px", "")
        }
        thisEl.css("--top", String(parentDistance + top).concat("px"))
        // Delete every ongoing animation
        killAnimation()
        // Create a new animation
        animation.current.push(gsap.to(thisEl, {left: maxLeft.current, duration: props.duration, ease: Linear.easeNone, onComplete: resetComponent}))
    }
    // Delete every ongoin animation
    function killAnimation(){
        for(let i = 0; i < animation.current.length; i++){
           animation.current[i].kill()
        }
        animation.current = []
   }
    // Exec when the site is loaded/the component refreshed
    useEffect(() => {
        if(isLoaded){
            updateWindow()
            $(window).on("resize", updateWindow)
        }
    }, [])
    // Reset a cloud (called when the component reaches the end)
    function resetComponent(){
        thisEl = $(`#${props.propId}`)
        thisEl.css("left", -2 * thisEl.width())
        killAnimation()
        animation.current.push(gsap.to(thisEl, {left: maxLeft.current, duration: props.duration, ease: Linear.easeNone, delay: props.delay, onComplete: resetComponent}))

    }
    // Return default cloud
    return(
        <div className="backgroundCloudContainer">
            <img src={props.background} className="backgroundCloud" id={props.propId} draggable="false" alt={props.propId}
            style={{
                "--z-index": props.zIndex,
                "--top": props.top,
                "--scale": props.scale
            }}/>
        </div>

        
    )
}

To fix the problem I did the following things:
1) Using an array to store every animation I create (so I can .kill() everything)
2) Using useRef() instead of saving data in plain variables

3) Fixed the event listeners because I inserted the jquery .off() method that removes every listener from the element that, of course, made my solution not working

 

Now I'm planning to remove the array and setting overwrite to "auto" or true so I'll save a piece of performance.
Anyway, thanks for helping me.
Hope that the problem I had will help someone else : D

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