Announcing Panorama.js A JavaScript/CSS3 Library to Replicate the Core Windows Phone Panorama Control
Since I first saw Metro UI on Windows Phone I have been fascinated with the various controls and user experience metaphors it introduced. These include the AppBar, Tiles and the Panorama and Pivot controls amongst others. A couple of years ago on my way to the Dallas Day of .NET I created my first version of a jQuery Panorama plugin. I based it on a parallax scroller library I found on Codrops. I likes it because it provided the background scrolling effects that helps make the Metro UI Panorama stand out.
wp_ss_20121230_0005.png
Over the past couple of years I keep modifying the plugin to add and remove functionality. The more I tinkered the larger the library got and the more issues I kept introducing and trying to patch. I finally got to a point where I decided to start from scratch. I decided to define a small set of features and create a library that was completely independent of jQuery and other third party libraries. jQuery independence was an important step for me because I am trying to wean my off jQuery as much as I can.
- Supports Multiple Panels (I used 4 in my examples)
- Provides a Peek or Gutter setting to tease the content to the right
- Can go either left or right
- Independent of mechanism to trigger sliding (no internal touch or mouse support)
- Is continuous
- Supports both single header or panel headers
So how does this work? There is a combination of things that work together in concert to make the panorama effect happen. First there has to be markup that organizes the content into panels. I generally like to use an UL, but I have done the effect with SPAN and DIV elements. The important thing is they have to support side by side display. The panorama library also supports a header, which I will cover later in the post. I also included a cascading stylesheet that should work with the previous situations.
<divclass="panorama-container"><headerclass="panorama-header"><h1class="big-header">Big Header Title</h1></header><ulclass="panorama-panels"><liclass="red-panel single-panel"></li><liclass="blue-panel single-panel"></li><liclass="green-panel single-panel"></li><liclass="purple-panel single-panel"></li></ul></div>
I included several examples with the code to demonstrate how the library works. I used them to test the library to make sure it works. I even did some unit tests for good measure, although I stopped because it was taking longer to write them than I wanted LOL. There is an example for both the big title and multiple header titles with a simple click event driven example.
Since I made it work without jQuery it works by selecting a HTMLNode. In the examples document.QuerySelector retrieves the main container node. Pass the container node to the Panorama function and it will set everything up for you. You can optionally pass an object with custom settings. If you have kept up with my blogging you should see a familiar pattern. The library follows the jQuery pattern.
var panels = document.querySelector(".panorama-container"), p = panorama(panels, {speed: 600}).moveNext(function (i) { console.log("moveNext"); }); panels.addEventListener('click', function (e) { //p.moveRight(e); p.moveLeft(e); }, false);
I tried to make just about everything configurable through a settings object. I wont got into full details, hopefully it is sort of self explanatory. Generally you wont need to override the default settings. The first few items are the selectors needed to make the library function. next are some width and height properties, then the easing setting.
settings: { panoramaSelector: ".panorama-panels", container: ".panorama-container", singleColumnSelector: ".single-panel", doubleColumnSelector: ".double-panel", speed: 150, //speed of each slide animation windowWidth: window.innerWidth, panelWidth: window.innerWidth, panelHeight: window.innerHeight, peekWidth: 35, easing: "ease-in-out", nextScroll: ".panorama-next", prevScroll: ".panorama-prev", navWrapper: ".panorama-navigation", showPrevNext: false, //do this when no touch available headerSlide: .2, bigHeaderLeft: 0, headerStyle: ".panorama-header", headerPanelStyle: ".panorama-panel-header", headerHeight: 40 }
There are two variations of the Metro UI panorama control, the panorama which typically sports a single header title. The other is the pivot control which has titles for each panel. Each one of the header options animates in the direction the panorama is moving. For the single title it moves a percentage of the width each time the panorama moves until it cycles around. Then it resets to the original position.
In the case of the pivot control each panel has an associated header. As the panels move the titles move so that the panel in view's title is more or less flush with the phone's left-hand side.
Internally the panorama library uses CSS3 transforms to perform the animations. Since this library should be used on a phone, it will work fine on the desktop but its more about the usage context, you can assume transforms are supported. It tests to see if 3D transforms are supported, if so it uses the 3D transform which should kick in the GPU.
As the panels are moved it uses the browser's transitionEnd event to 'clean up' the markup. Depending on the direction the panels move it will either move the first panel to the end of the list or the last panel to the front of the list and adjust the positioning. This is how the panorama is continuous.
Finally I added grunt.js support to minimize the library. It included a panorama.min.js file in case you don't have grunt.js setup on your development machine.
This is my first real time trying to make a library publicly available on GitHub, so I hope I have not messed that part of too bad. I gave the library an MIT license thinking it would be the right license to make it very available to anyone to use, that and jQuery uses it. So enjoy and I hope you find it useful. Please send me your comments. I will periodically post updates to the library as I have time.