Jump to content
GreenSock

PawleyBoboli

Accordion menu with GSAP

Recommended Posts

Hi Folks,  my first post to this forum.  I've been using GSAP for Flash for years, but now trying to get a handle on working in JavaScript.  GSAP for JS is a big help.

 

I am working on a custom accordion menu and it mostly works, but has a bug where altering the  "selected" look of a clicked button stops working after multiple clicks.  i have created a CodePen project here: 

See the Pen gjAxC by PawleyBoboli (@PawleyBoboli) on CodePen

 

Notes:

  • I put this together from pieces of another example I found on the forum, but can't find again (sorry, too tired)
  • I am using TimeLineLite to tween the addition of a class for the selected "active" item , and removal of the class for all others.
  • It's working for the Module buttons, but for the Chapters inside a module, it stops highlighting your selection after clicking between 2 items repeatedly.  Example:
    • Open "SECTION MODULE 2"
    • Click the 1st item - it highlights
    • click the 2nd item - it highlights and the 1st one returns to previous state
    • now click back & forth between them -  all highlights stop working.

I think my problem is related to the adding and removing of the ".activeChap" class but I am not sure.  I have commented my code.  Any help is greatly appreciated.

 

--Kevin

Link to comment
Share on other sites

WHups... just discovered this accordion is not working at all in FireFox - but it does in Chrome and Safari.  Gonna need to address that too eventually.

 

--Kevin

Link to comment
Share on other sites

Hello PawleyBoboli,

 

Try this:

 

Working example:

See the Pen vqnKJ by jonathan (@jonathan) on CodePen

 

You just need to add the event argument for your click handlers, you were getting a undefined variable for event for event.preventDefault()

ReferenceError: event is not defined
http://s.codepen.io/boomerang/f274091ca626ee6bac5789f887df3a241393516670185/index.html
Line 265

The below 2 click handlers were missing the event argument in the anonymous function:

// missing event in anonymous function
$chapterLi.click(function(event) { 
      event.preventDefault(); 
});

// missing event in anonymous function
$sidemenuLi.click(function(event) { 
       event.preventDefault(); 
});

Does that help? :)

  • Like 2
Link to comment
Share on other sites

Hi Kevin,

 

Also you're not tweening the <a> tag color to rgba(255,255,255,1).

 

Try this:

// MENU CHAPTER SELECTION
$chapterLi.click(function(event) {
  event.preventDefault();
  var $this = $(this);

  var newClick = new TimelineLite();

  // this next line seems unnecessary since adding and removing the "activeMod" class should revert the alpha but it does not.
  newClick.to($chapterLi.filter(".activeChap").find("a"), 0.15, {color:"rgba(255,255,255,0.5)"}, 0);
  newClick.set($chapterLi.filter(".activeChap"), {className: "-=activeChap"}, 0);
  newClick.to($this, 0.15, {className: "+=activeChap"}, 0);
  newClick.to($this.find("a"), 0.15, {color:"rgba(255,255,255,1)"}, 0);
});

Also on a side note the engine has a set() method that allows you to create zero duration instances:

var tl = new TimelineLite();

// a zero duration instance
tl.set(element, {vars});

// this has the same effect 
tl.to(element, 0, {vars});

// Also can be used in single instances
TweenLite.set(element, {vars});

TweenMax.set(element, {vars});

Rodrigo.

  • Like 2
Link to comment
Share on other sites

Thanks both Rodrigo & Jonathan.  Your input fixed both the highlight problem and the bug with FireFox.

 

FWIW, I had created classes in my CSS for the active state of each button type.  I figured when adding and removing the classes to the button instances would apply/remove those styles.  Instead, using Rodrigo's code for tweening the CSS styles worked as long as I removed the classes from my CSS sheet.  So in effect, I am now just using the classes as flags to determine the selected/active button, and changing the CSS with tweens.

 

I have made a revised fork with everything working here: 

See the Pen ofhqg by PawleyBoboli (@PawleyBoboli) on CodePen

 

Thanks so much!

--Kevin

  • Like 1
Link to comment
Share on other sites

Great Job.. glad you got it figured out :)

Link to comment
Share on other sites

You're welcome Kevin.

 

You might want to explore attaching the click event to the elements in the same way you did with the hover element, like that on click you can play that timeline and reverse the timeline of the rest of the element with the active class. You save some code execution by creating the timeline just once and accessing the instance on the click event and a traversing the DOM searching for those elements. For menus I always work like that, it saves you some code, specially if your event handlers executes a lot of functions.

$(".boxBtn").each(function(index, element){
  var hoverTl = new TimelineLite({paused:true}),
      clickTl = new TimelineLite({paused:true});
  hoverTl.to($(element).find("a"), 0.15, {color:"rgba(255,255,255,1)"}, 0);
  element.hvranimation = hoverTl;

  clickTl
    .to(element, 0.15, {className: "+=activeChap"}, 0)
    .to($("element a"), 0.15, {color:"rgba(255,255,255,1)"}, 0);

  element.clkAnimation = clickTl;
})
//also you can chain the click event
.click(function(event)
{
  event.preventDefault();

  // reverse the active button's tween
  $(".activeChap")[0].clkAnimation.reverse();

  this.clkAnimation.play();

});

Rodrigo.

Link to comment
Share on other sites

Thanks again for these tips Rodrigo.  I am being exposed for the poser JScript/JQuery newbie that I am.  I am still trying to get a handle on all the possibilities, and my head is still thinking ActionScript.

 

I have incorporated your suggestions in a new codepen fork here: 

See the Pen Ltlvs by PawleyBoboli (@PawleyBoboli) on CodePen

  and they do clean up alot of my code.  

 

I added a test inside each click function for the existence of the "activeMod" and "activeChap" classes since errors were thrown if they did not exist (like at init).  The new code works, but as before, if you click quickly back & forth between 2 chapter buttons, they will stop working.  I think this might have something to with the timelines not completing between clicks?  I tried changing the clickTl  to 

.set(element, {className: "+=activeChap"}, 0)

but that did not work.  I also tried setting the duration of that tween to a very small number like 0.01, but also no go.

 

I appreciate your continued input on this.  Thanks

--Kevin

Link to comment
Share on other sites

Hey Kevin,

 

Mhhh maybe try removing the className instance from the timeline. When you go back and forth between two links before their timelines are completed, you might have two elements with the activeChap class on it, causing this unwanted behaviour. So you can remove that from each element's timeline and add/remove the class in the click event, maybe like this:

// MENU CHAPTER SELECTION
$(".boxBtn").click(function(event) {
  event.preventDefault();
  
  // reverse the active button's tween
  if ($(".activeChap")[0]) {
    $(".activeChap")[0].clkAnimation.reverse();
    TweenLite.set(".activeChap", {className:"-=activeChap"});
  }

  this.clkAnimation.play();
  TweenLite.set(this, {className:"+=activeChap"})
});

Like that you'll always have just one element with the active class in it.

 

Also I don't see(unless I'm getting it wrong) any reason to reverse the hover animation on the click event, the over/out events will handle that animation themselves, no need to control it from another event handler, that's why I removed it from the code.

 

Rodrigo.

  • Like 1
Link to comment
Share on other sites

Thanks again Rodrigo.  This works much better.

 

As for reversing the hover animation on click, I found it is necessary.  Since both timelines "clkAnimation" and "hvranimation" set the same color CSS attributes at the end of their sequences, reversing just the "clkAnimation" does not return the color to it's initial state if the "hvranimation" is still at the end of it's timeline.  I think it's because your mouse hovers over a button in order to click it, so that timeline is also gets run and stays in effect until you hover out.

 

Actually, it doesn't make sense to me, because in order to click a different button, one must hover out of the last selected button thereby reversing its "hvranimation" timeline.  so it shouldn't make a difference -  but for whatever reason, it doesn't work without reversing both timelines.

 

--Kevin

Link to comment
Share on other sites

Hi Kevin,

 

Actually is an expected behaviour.

 

First you hover the element and then you click it. When you hover the element the hover tween starts as expected. Then when you click on the element the click tween starts. It is important to keep in mind that both instances target the same element and properties. If the click timeline starts when the hover timeline is playing (which is very difficult in your case because of their short durations), the overwrite manager comes into the picture and what it does it gives control of the element and it's properties to the last tween being played. So if the hover tween is playing and you click an element the click tween takes control of the element and the color property. At the same time the overwrite manager kills the other tween and send it to garbage collection. If you make those instances longer you'll see that behaviour.

 

In order to avoid this you have to add an extra parameter in the config object of the instances, in order to tell the overwrite manager that no instance should be killed:

$(".boxBtn").each(function(index, element){
  var hoverTl = new TimelineLite({paused:true});
  var clickTl = new TimelineLite({paused:true});
  
  hoverTl.to($(element).find("a"), 0.15, {color:"rgba(255,255,255,1)", overwrite:"false"}, 0);
  element.hvranimation = hoverTl;
  
  clickTl
    //.to(element, 0.15, {className: "+=activeChap"}, 0)
    .to($("element a"), 0.15, {color:"rgba(255,255,255,1)", overwrite:"false"}, 0);

  element.clkAnimation = clickTl;
});

Like that you won't need to reverse the hover animation in the click event, it should reverse on the out event but it'll make the click timeline useless because the active link will have the same color opacity as the rest of the elements. This also creates an issue with the starting values of your instances, which may require fromTo() instances, but this won't look good, because if you're hovering the element and then click on it it will go from opacity 0.5 to opacity 1.

 

I believe that the code you already have is doing the work fine and the result looks very good, so my recommendation will be to keep it as it is. If it ain't broken don't fix it :D

 

Rodrigo.

  • Like 1
Link to comment
Share on other sites

  • 10 months later...

Hi, is there an example available to create the same menu only in AS3? Thanks for any tips!

Link to comment
Share on other sites

dada78, not that I know of. 

Link to comment
Share on other sites

Hi,

 

Some time ago I had the same question. Unfortunately I've drifted away from AS3 (in fact I still have Flash CS4 installed, no need to renew the license), so I don't have an fla file to share. But here's a post in the actionscript.org forums with a couple of code snippets that might help you get started:

 

http://www.actionscript.org/forums/showthread.php3?t=277297

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