Re-size content pane based on open ratio

Hey guys,

So what I want to achieve is that as you open the content pane, based on the ratio of how open it is, the main content shrinks.
Basically I am trying to emulate the airbnb application on ios when you open their side menu.

I started trying to play around with the height and width of the pane but no luck so far. If anyone has any ideas some help would be appreciated :smile:

3 Likes

The <side-menu-content> directive exposes $scope.sideMenuContentTranslateX - you may be able to $watch this and set a 3d value on the <side-menu-content>.

Itā€™s a starting point :slight_smile:

cool thanks! I will try that now and I will post any updates.

well this is what I have so far. Itā€™s not perfect and needs a bit of tinkering, but IMO itā€™s a good start:

    app.directive('shrink', function($timeout) {
        return {
            restrict: 'A',
            link: function($scope, $element, $attr) {
                // Run in the next scope digest
                $timeout(function() {                
                    // Watch for changes to the x var which is a value between 0 and 275
                    $scope.$watch('sideMenuContentTranslateX', function(x) {
                        var toScale =  (1- Math.abs(x/275));
                        //we do not want the side menu to be less than 70 percent of it's original size
                        if(toScale > 0.7){
                            $element[0].style.webkitTransform += ' scaleY('+ toScale +')';
                        }
//if we are at the end of the animation then skew it
                        if(x === 275){
                            $element[0].style.webkitTransform += ' scaleY(0.7) skewY(-20deg)';
                        }
                    });
                });
            }
        };
    });

@mlovekovsky Where are you applying this directive to, the whole side menu directive or just the side menu content?

I am applying this directive just to the side menu content part so the HTML looks like:

  <side-menus>
        <!-- Center content-->
        <pane side-menu-content nav-router shrink>
....
</pane>

@mlovekovsky Looks a little funky but itā€™s a good start. You should take a look at this article about 3d transforms. Instead of scaleY, try rotateY. It seems this could be a better way to product the desired effect.

thanks for the heads up! Going to play around with the different transforms, rotateY would be better since it would prevent the images looking squished

I think a lot of what will make this work is the handling of the background. In your example, the area behind the content has color to differentiate between the two. Also, check out the fade bar directive the ionic guys made up. You can set a value to change as the ratio changes.

.directive('fadeBar', function ($timeout) {
    return {
        restrict: 'E',
        template: '<div class="fade-bar"></div>',
        replace: true,
        link: function ($scope, $element, $attr) {
            // Run in the next scope digest
            $timeout(function () {
                // Watch for changes to the openRatio which is a value between 0 and 1 that says how "open" the side menu is
                $scope.$watch('sideMenuController.getOpenRatio()', function (ratio) {
                    // Set the transparency of the fade bar
                    $element[0].style.opacity = Math.abs(ratio);
                });
            });
        }
    };
})

well I based myself off of the fade bar example.
What I did was I made my side-menu takes up 100% of the screen, so that when the side ā€œshrinks awayā€ it does so with the background color still visible.
I wanted to use a fade bar, but my background is a gradient, so it looks kind of awkward if part of it fades on the top.
Hope what I wrote makes sense heh

@mlovekovsky, so I have a few codepens that I got together that I think could do the trick.
The first one just shows how to work with the getOpenRatio event for the sideMenuController.

Here Iā€™m fading the content base on how open the menu is. In this one, Iā€™m playing with some css 3d transforms to get the effect that seems similar to that first image you posted. These two examples could get you in the right direction.

The only thing Iā€™m curious about is how to set these values based on the open ratioā€¦that is how can a value of 0 or 1 be used to go between all the css values needed. What do you think?

Dragging breaks thisā€¦but I think its closeā€¦tap on the menu button

2 Likes

hmm ya working with the ratio is a bit more complex since you need to find a the proper way of calculating what values to attribute to the CSS.

What works a bit better IMO is to work with the sideMenuContentTranslateX value. If you know your X limit (i.e. in my case it is 275px) then I create an inverse proportion of how much to scale by: var toScale = (1 - Math.abs(x / 275));

So then to make it menu smaller as it moves to the side I would do something like:

$element[0].style.webkitTransform += ' scaleY(' + toScale + ')';

Does that make sense?

thatā€™s a really nice effect! I am going to play around with it to see how it can be more graceful on drag

I have another quick question.
If I scale it too much, then the main content simply goes off the screen. Do you know how to limit how much the side menu slides by.
Currently the default is 275px, but if letā€™s say I want to block the side menu to only slide 120px instead, how would I go about doing that?

Thanks

You can do into the sass files and change the variable that dictates the width of the side menu content then build your own version of ionic that way. The Ionic guys have a nice tutorial on customizing the sass files so take a look at it

awesome thanks!

To simplify the problem what I did was disable the drag (sine the interaction got a little funky when dragging).
Then my directive became super simple!

 .directive('shrink', function($timeout) {
    return {
        restrict: 'A',
        link: function($scope, $element, $attr) {
            // Run in the next scope digest
            $timeout(function() {
                // Watch for changes to the x var which is a value between 0 and 275
                $scope.$watch('sideMenuContentTranslateX', function(x) {
                    if (x === 275) {
                        $element[0].style.webkitTransform += ' scaleY(0.6) scaleX(0.6) translateX(-140px)';// skewY(-20deg)';
                    }
                });
            });
        }
    };

I scale it down then I push the menu back on the screen. It doesnā€™t have the ā€œopen doorā€ effect but it does have a nice shrinking away effect.
I will take a look at the SASS tutoril now so I donā€™t have to do the translateX(-140px) part in the directive.

Thanks for all your help!

hmm i noticed something weird.
After shrinking the content I noticed itā€™s still active.
So when itā€™s small and to the side i can scroll it and actually click on the elements to navigate it.
Any idea on how to disable that?

This is true when using the default slide function. Itā€™s something Iā€™ve noticed and iā€™m not quite sure how to fix it. I know JQM creates a div that overlays the whole content and when the user taps that, it toggles the menu to close.

Maybe a similar method can be applied to watch touches on the content pane and toggle the menu to close?

@mharington I noticed this too, good point. can you open an issue about it?