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?).
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!
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.
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.
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.
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
:
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.
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.