Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
sammyg

Trigger animation only on clicked element using class selector

Recommended Posts

Hi,

 

I'm new to GSAP, I found it on codepen when looking for an animation for a map marker. I really like using it so far, but I've run into a bit of an issue. The example I found had only one element that could be clicked on based on an id selector. I've modified it to fit my needs, but can't figure out how to have the animation fire for only the clicked element. I tried a few solutions like:

 

  var clicked;

  $c.root.on('click', function(e) {
    clicked = $(e.target).closest('.card');
    console.log(clicked);
    toggleCard(clicked);
  });

 

Which definitely picks up the element that is clicked, but I can't get the animation to then fire.

 

Any help would be appreciated, thanks!

See the Pen NMPLKy by samandalso (@samandalso) on CodePen

Link to post
Share on other sites

Hi and welcome to the GreenSock forums,

 

Thanks for the demo.

Instead of trying to figure out what all the code in your demo was doing I decided to make a very basic example of multiple elements having timelines that change their direction (open / close) when you click on them.

 

I use a jQuery each() to construct timelines for each element. This approach assumes each card will have the same type of child elements.

 

Click on the cards:

 

See the Pen qYqKEy?editors=0010 by GreenSock (@GreenSock) on CodePen

 

  • Like 4
Link to post
Share on other sites

Hi @sammyg :)

 

Welcome to the forum.

 

In addition to Professor @Carl's excellent advice, I'll throw an additional two cent thought out here for you. The original pen you forked for your demo is a cool effect, but it's only one little panel. When you have multiple little pop-up panels you'll have to decide what to do when one is clicked while another is open. Do they all open and close independently like Carl's demo? Or does the open one have to close when a new one is clicked/opened? If so, should the open panel fully reverse before a new one opens or does the active one close and the new one opens at the same time?  All methods are certainly possible, you just have to decide how it should behave. 

 

Happy tweening and welcome aboard.

:)

 

  • Like 4
Link to post
Share on other sites

@Carl @PointC

 

Thank you both for the advice, I'll take a closer look at the pen you posted, I was considering an each loop so that sounds like it might be the right path.

 

PointC, good points on what happens to each when the others are being interacted with or when someone clicks elsewhere on the page. All good things to consider.

 

I'll let you know how it goes.

 

-Sam

  • Like 2
Link to post
Share on other sites

@Carl I've gotten much closer using your example:

 

See the Pen NMPLKy by samandalso (@samandalso) on CodePen

 

Do you have any advice for detecting when the animation is reversing? tried adding in a rev variable but it doesn't look right to me and it's not working :P I'd like to speed up a few of the tweens on the way out! Thanks again for the advice, it's a really fun and smooth animation library.

Link to post
Share on other sites

Nice job getting things to work in your demo!

 

There really isn't a clean way to reverse a timeline and make some of the tweens faster. You pretty much have to speed up or slow down the whole timeline.

I changed your click code to make the timeline play twice as fast on reverse. I went for a more long-hand conditional statement so its all easier to read

 

$('.card').click(function(){
  if(this.animation.reversed()){
      this.animation.play().timeScale(1);
  }    else {
      this.animation.reverse().timeScale(2);
  }
})

 

 

See the Pen yjbVdg?editors=0010 by GreenSock (@GreenSock) on CodePen

 

in case you are new to timeScale: https://greensock.com/docs/TimelineLite/timeScale

 

  • Like 3
Link to post
Share on other sites

@Carl Awesome, thanks I got it working now. One more question, I've searched around, any advice on closing other open instance when another marker is clicked? Or when the DOM is clicked, something like:

 

$(body).on('click', function() {
	$('.map-card').each(function() {
      if(this.animation.reversed()){
      }    else {
        this.animation.reverse().timeScale(1.7);
      }      
    })
});

 

Link to post
Share on other sites

I found a demo that did something similar. The basic idea is that you use a global variable to reference whatever the current or active animation is.

Whenever you click on something you check to see if there is a currentAnimation, and if so, you reverse it

 

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

 

  • Like 3
Link to post
Share on other sites

@Carl Hi, one more question for you if you have a chance. I've been changing up how this works a bit and found a great example here: 

 

See the Pen LmOqMp by samandalso (@samandalso) on CodePen

 

 

I've integrated a lot of this with my example:

 

See the Pen KRyJNQ by samandalso (@samandalso) on CodePen

 

Which is working pretty well. I'm having trouble figuring out how to disable the click event on the card itself and add it to the close button. Any tips or pointers?

 

Link to post
Share on other sites
7 hours ago, Sahil said:

Easiest way would be to change your click handler to header so your map card won't listen to click event.

 

@Sahil Thank you that looks great. I was curious about how this is working.

 

So this is stopping the event from firing until you run the if condition:

 

event.stopPropagation();

 

Then you're checking if the target of the event has a class list and if the .map-card__header class is in that list and if so find the parent with the class of .map-card and make that the target of the event? Which sets the target in the button function below?

 

if (
  target.classList &&
  target.classList.contains("map-card__header") &&
  target.classList.contains("map-card__header")
) {
  target = target.closest(".map-card");
}

 

Is the second check for the header class necessary in the if condition?

 

Anything else that I might be missing?

 

Link to post
Share on other sites

It was supposed to be,

 

if (
  target.classList 
  && (target.classList.contains("map-card__header") 
      || target.classList.contains("map-card__close"))
) {
  target = target.closest('.map-card');
}

 

Why it still worked then? Because in your demo if dataset.mapCard is undefined then animation would reverse.

 

See the Pen QrQNKd?editors=0010 by Sahil89 (@Sahil89) on CodePen

 

Quote

event.stopPropagation();

 

That is used to stop event bubbling. What was happening was, you were listening to click event on map card and close button so when you clicked on close icon, your timeline would start reversing but then even would get bubbled to the parent that is map card and it would again play your animation so you must have felt that close doesn't work.

 

In following demo animation is set to play or reverse when you click on '.container' but all three elements are listening to click event. So

 

1. if you click on edge of container then animation will play or reverse.

2. If you click on edge of wrapper then nothing will happen because event is getting bubbled twice

3. but if you click on center then animation will play or reverse because event is getting bubbled three times. So lets say animation is reversed, it will start reversing then playing and again reversing but you will only see it getting reversing because everything happens at the same time.

 

 

See the Pen qYxNBB?editors=0010 by Sahil89 (@Sahil89) on CodePen

 

 

 

  • Like 4
Link to post
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.

×