ngCurtain
A set of pure AngularJS directives to create a wicked-cool "rising curtain" effect to unroll the sections of your website.
Trust me. It's epic.
What is it?

In a word: victory.

ngCurtain is a set of directives for AngularJS applications to create the "rising curtain" scrolling effect you see on this page.

This project is based, in part, on the no-longer-maintained curtain.js for jQuery, but contains some improvements that AngularJS makes easy. Not all features have yet been ported. For an up-to-date list, check out Issue #1 on GitHub.

Bower installation instructions are in the next section, but if you want the source code, visit the GitHub project page.

This is alpha quality software and contributions are welcomed. Please feel free to contact me, file an issue, or send a pull request (well, aren't you thoughtful?).

Usage

1. Install It

ngCurtain is available through Bower, so this is by far the easiest way to obtain it. Just run:

$ bower install --save-dev ng-curtain

This will download the latest version of ngCurtain and install it into your Bower directory (defaults to components). Boom!

2. Incorporate It

Now you have to add the script file to your application. You can, of course, just add a script tag. If you're using ngBoilerplate or any of its derivatives, simply add it to the vendor.js array of your Gruntfile.js:

vendor: {
  js: [
    // ...
    'vendor/ng-curtain/ng-curtain.min.js',
    // ...
  ]
},

However you get it there, as soon as it's in your build path, you need to tell your app module to depend on it:

angular.module( 'myApp', [ 'ngCurtain', /* other deps */ ] );

Also be sure to include the stylesheet. In ngBoilerplate, simply import ng-curtain.less into your main.less file.

Now you're ready to go! Sweet.

3. Use It

The markup for ngCurtain is fairly straightforward. There are two directives: ctnCurtains and ctnCurtain. The former is the main directive and wraps all content, accepting within it as many of the latter as necessary, each representing a separate curtain whose position to manage. Both can be used either as elements or as attributes.

For example, the typical structure of ngCurtain therefore looks something like this:


  

Check out this demo's source code for a more detailed example.


How it Works

If you're just interesting in using ngCurtain, you can ignore this section completely. But for those curious, this section contains an overview of how the code works.

The outer directive (ctnCurtains) contains the vast majority of the logic as methods on its scope. The inner directives (ctnCurtain) require the outer directive and call a method during their linking phase to register their presence.

After initialization of all the children, ctnCurtains calculates the positions of all the individual ctnCurtain elements that registered themselves, calculates the total window height, and determines which curtains to start where based on the current value of $location.path(). This same process is repeated every time the window is resized.

Technically, all cards start positioned at 0,0 and the window's height is manually calculated and applied as the sum of the heights of the individual curtains.

When the browser window scrolls, the ctnCurtains directive determines whether we are scrolling within a curtain, beyond a curtain, or above a curtain and arranges the positions and stacks appropriately and applies translateY operations to change the current vertical position of the curtain relative to the current (virtual) scroll position. That probably sounds confusing, but if you look at the code, it's pretty straightforward.

ngCurtain API

Attribute: ctnCover

While all curtains have a minimum height of the window height, it is not always desirable to allow some curtains to extend beyond the window height. For example, covers (like the first curtain here) make sense to not overflow the window as they are an "intro" whose display we want to control responsively. Setting the ctnCover attribute on a curtain to true will ensure the curtain does not exceed the current window height.

ctnCover takes an expression, but that expression is never re-evaluated as it does not make sense to convert something that once was a cover into no longer a cover, and vice versa. The simplest use case is just the value true:

Class: current

Whichever ctnCurtain is currently active is given the class current (this can be configured in the template).

No styles are by default associated with this class.

Class: hidden

When a ctnCurtain is not visible - either as the current curtain or the following or preceding curtain, if visible - it is assigned the hidden class (this can be configured in the template).

By default, this simply sets display: none on the curtain.