Jump to content
GreenSock

failure13

Collapse with GS (bootstrap-like)

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hi guys!

First of all great new site, looks awesome, even though a little bit lost on content sometimes, but it will come back soon i guess :)

 

I just had to ask, since now i'm working on making stuff like bootstrap collapse throguh greensock (coz bootstrap's is pretty laggy)

And i came across few problems....Like for example in Firefox animation of such collapse is almost twice less speed than on Chrome (but it's kinda content dependant, if you slide something like li or text it's ok, but if it's some complex structure or div which have table inside of it - it's really bad). I was trying to forse 3D and stuff like that, it doesn't seem to work very well.

 

And then when i was just sweeping around cool new docs, i've found that you have 'Show more' button which doesn't lag anywhere, even though there are a lot of different content inside!

http://greensock.com/docs/#/HTML5/GSAP/Utils/SplitText/

 

Could you please share the code of how you made it work so extremely good and with consistant speed around browsers?

Link to comment
Share on other sites

My God...

It's unbelivable that i seem to find source of my problem, which was...svg antialiasing fix.

svg {
    shape-rendering: geometricPrecision;
    -webkit-transform: translateZ(0.1px);
    -moz-transform: translateZ(0.1px);
    -o-transform: translateZ(0.1px);
    transform: translateZ(0.1px);
}

So it seems that each time i've run any tween which changed height dinamically it caused repaint of all SVG elements on z axis by 0.1px AGAIN!

And as far as my research goes it was really all elements, not only those which are below collapsible element (which would be logical, knowing browsers reflow / repaint), but every of them on page.

At least in Firefox it is very noticeable hit on perfomance.

 

So at first i've done some body class svgAA and written my CSS like .svgAA svg, then removed this class onupdate and added it back again onComplete, this worked extremely good in terms of perfomance, but jumping all svgs each time was pretty hardcore experience visually, especially if tween is longer than 0.5 seconds...

Then i thought like wtf, why not use simple margin instead?

svg {
    margin-left: 0.5px;
    shape-rendering: geometricPrecision;
}

Seem to work very well by now!

 

Hope this will help somebody, i've exploaded my head around this issue a lot.

Of course it's compromise solution since it makes svgs crisp, but you have to keep in mind shift on 0.5px to fix it visually later.

 

Any other solutions are welcome :)

And i still very interested to see workflow of Show more button in docs! ))

 

P.S. I've found that it's better to use:

svg {
    margin-left: 0.5px;
    shape-rendering: geometricPrecision;
}

For some reason it doesn't shift svg visually, but all of them seem to have crisp lines and antialiased round edges :)

  • Like 1
Link to comment
Share on other sites

Thanks for sharing your solution. Yeah, I was gonna say - it sounded like it must be some rendering issue on your end. As far as what we do in the docs, it's a pretty simple animation of the "height" of the <div>. Nothin' fancy. 

  • Like 2
Link to comment
Share on other sites

Wow, really?)

I thought it's something more fancy! :D

 

Anyway it seems there is bug on new forum, you can't write  "margin-left: MINUS0.5px;" in code or quote tag, whenever you write minus it just cuts whole line to ";"

Hope it will be fixed, coz it's pretty vital for some codes :))

Link to comment
Share on other sites

So i've made a nice collapse for AngularJS, looks like that:


LavkaModule.directive('collapse', function() {
    return {
        restrict: 'A',
        scope: {
            collapse: '='
        },
        link: function(scope, element, attrs) {
            var target = attrs.collapse ? element : $(attrs.target),
                collapsed = attrs.open || attrs.collapse ? false : true
            ;

            function opened() {
                t.invalidate();
                TweenMax.set(target, {height: 'auto', overflow: 'visible'});
            }
            function closed() {
                TweenMax.set(target, {overflow: 'hidden'});
            }

            if (!target.data('initHeight')) {
                target.data('initHeight', target.height());

                var t = TweenMax.to(target, 0.4, {
                    overflow: 'hidden',
                    height: 0,
                    marginTop: 0,
                    marginBottom: 0,
                    ease: Power1.easeInOut,
                    paused: true,
                    reversed: true,
                    onStart: closed,
                    onReverseComplete: opened
                });

                if (collapsed) {
                    TweenMax.set(target, {
                        overflow: 'hidden',
                        height: 0,
                        marginTop: 0,
                        marginBottom: 0
                    });
                }

                element.bind('click', function() {
                    if (t.reversed()) {
                        t.play();
                    } else {
                        t.reverse();
                    }
                });
            }

        }
    }
});

My problem is that if i intialize it as collapsed state, on this lines:

                if (collapsed) {
                    TweenMax.set(target, {
                        overflow: 'hidden',
                        height: 0,
                        marginTop: 0,
                        marginBottom: 0
                    });
                    t.play();
                }

Than i need to press couple of times to see opening animation without glitch..

 

I'm a little confused now looking at this logic, but thing is that if i initialize element as collapse, i have to say click function that it need to change direction first time, and than go eaxctly like it's now...

 

Any ideas?

 

P.S. Sorry, no time for codepen right now, maybe later that day i'll do it!

Link to comment
Share on other sites

hmmm, really not sure what you mean by code with minus signs or dashes will collapse. I made a little test that appears to work fine:

#id {
  margin-top:-20px;
  left:-30px;
}

TweenLite.to(el, 0.2, {x:-20, y:"-20"});

perhaps a temporary glitch. not sure.

 

As far as toggling the height, here is a neat discussion: http://greensock.com/forums/topic/7200-replacing-jquery-slidetoggle/?hl=height%3Aauto

 

worth reading the whole thing, but the last solution is probably best.

 

If you need more help, please make a reduced CodePen. Thanks

Link to comment
Share on other sites

Doesn't seem to be temporary, probably it's connected to my account somehow...

You can see it here again, it always happens for me, even now http://i.imgur.com/eLCHAfu.png

 

I use nothing funky, just latest firefox + AdBlock.

 

About discussion - yeah, i've found it before also, really great solutions, i use some sort of mix from them which fits my situation...

Now i come up with working solution like here:


LavkaModule.directive('lavkaCollapse', function() {
    return {
        restrict: 'A',
        link: function($scope, element, attrs) {
            var target = attrs.collapse ? element : $(attrs.target),
                collapsed = attrs.open || attrs.collapse ? false : true
            ;

            function opened() {
                t.invalidate();
                TweenMax.set(target, {height: 'auto', overflow: 'visible'});
            }
            function closed() {
                TweenMax.set(target, {overflow: 'hidden'});
            }

            if (!target.data('firstBlood')) {
                target.data('firstBlood', true);

                var t = TweenMax.to(target, 0.4, {
                    overflow: 'hidden',
                    height: 0,
                    marginTop: 0,
                    marginBottom: 0,
                    ease: Power1.easeInOut,
                    paused: true,
                    reversed: true,
                    onStart: closed,
                    onReverseComplete: opened
                });

                if (collapsed) {
                    t.timeScale(100);
                    t.play();
                }

                element.bind('click', function() {
                    t.timeScale(1);
                    if (t.reversed()) {
                        t.play();
                    } else {
                        t.reverse();
                    }
                });
            }

            if (attrs.collapse) {
                element.unbind('click');
                var collapse = attrs.collapse;
                $scope.$watch(collapse, function(collapse) {
                    t.timeScale(1);
                    if (collapse) {
                        t.play();
                    }
                    else {
                        t.reverse();
                    }
                });
            }

        }
    }
});

This dirty trick here seems to do the trick with dirty initialization of collapsed state :D

                if (collapsed) {
                    t.timeScale(100);
                    t.play();
                }

But now i have another problem, it's kinda not GSAP, but angular related, since it's unversal collapse directive, a lot of times i have a situation of for example using collapsing div with ng-repeat inside it, therefore each time i have such div in collapsed state, and it's children adds or removes some content in it's dom - i must recalculate height of tween so there won't be jump or no animation...

Not sure what to do really, in terms of what event to use in such case to detect changes.

 

There are some stuff like DOMNodeInserted which ain't crossbrowser solution...

So anyway, if someone who are experienced in angular will have an advise for me here - it would be awesome! :)

Their community is really poor now :\

 

I guess if i could find such event (maybe something angular native even, can't seem to find it), then t.invalidate(); should do the trcik of recalc..

 

P.S. Again sorry for no codepen, working here 24/7, absolutely have no spare time to make it right now :(

Link to comment
Share on other sites

  • 1 month later...

Hi failure13,

 

It's kind of hard to tell what you are trying to do, but it looks like you are forcing Angular to act like jQuery, which is a no-no.  In the Angular world, jQuery should only be used as a last resort.  There is usually an Angular way of doing things i.e. ng-click, ng-mouse*, ng-key*, etc...

 

I also noticed in your screenshot that you created an animation module for ng-scope, which is another no-no.  ng-scope can be used by other elements so your animations may not work correctly.  Only create animation modules with class names that you create.

 

I created a Plunk that uses no jQuery to help you out.  The collapse directive uses the $animate service and will work with an ng-repeat inside of it.

 

http://plnkr.co/edit/wHUybThuY2qt4iAv5k7u?p=preview

 

Blake

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