Adding awesome mini views to your web apps

"It’s appealing because it *resembles* what it’s representing, whereas [a scrollbar] *symbolizes* that. It’s the difference between ‘bang’ and ‘the sound a gun makes when it’s shot’."Awesome bars put the UI element in context. Searching for a specific spot in a document doesn't require scanning blindly through the whole thing via a small portal. ## Types of interaction In Mandays, the awesome bar allows interaction, and (controversially) replaces the native scrollbar. It simply provides you with a bit more context on where you are navigating too.
In our backlog management app called Truestory, the awesome bar can actually be interacted with directly. Though it has drag and drop of the main list, it was always a pain to take a story from the bottom to the top. With the awesome bar involved, we can drag stories to the approximate place in the backlog directly via the mini view.
However, some minibars don't have any interactive elements, and are purely informational.
Building an awesome bar for a blog
As an example, I have built a very simple HTML application that demonstrates the minibar in use on a blog post with comments. The rationale for this is that it is often hard to tell from a scrollbar how long a given post is, and what percentage of the page is filled with comments. To cut to the chase, have a look at the demo here, or poke about with the source here.
This is a read-only awesome bar, and just shows which bit of the page you are viewing. The nice thing about it is that the concept is really simple, and therefore easy to tweak. I have used JQuery here to make it simpler, but you may want to replace those parts with your library of choice (things like offset and position of DOM elements are made easy by it).
Some canvas basics
I decided to use a canvas element for this example but SVG plus raphael.js, would have been just as easy. There is a library to make canvas work on IE, but I haven't bothered with it here.
If you haven't used canvas before, all you really need to know for this example is that you can draw rectangles like so:
1 ctx.fillRect(left_offset, top_offset, width, height);The zero coordinate is the top left of the canvas by default, hence the left_offset and top_offset.
Layout
First I created a simple CSS layout with the blog post and comments on the left, and a position:fixed minibar on the right.
Encapsulating the minibar code
Next comes a small MiniBar function that we can create with the necessary configuration. When it is initialised, it sets the #minibar div and the canvas inside it to the height of the window (this would need to be bound to window resize in a proper application).
1 var resize_canvas = function(){ 2 canvas.height = $(window).height(); 3 };
Small potential gotcha is that canvas elements behave like images, and if you set the dimensions with CSS, the content of the canvas is scaled as well. What we are doing here is more like the following:
1 <canvas height="PIXELS" ></canvas>Adopting a simpl[istic] scale factor
Once the canvas is set to the right height, we set about drawing the elements onto it. This is really easy, and just involves multiplying the height of the elements in the DOM with a scale factor derived from the ratio between the entire document and the viewable area.
The scale factor looks like this:
1 var scale_factor = function(){ 2 return $(window).height() / holder_elem.height(); 3 }
using the height of the body is probably more reliable if you have a header and footer etc.
Drawing some stuff
The first thing we draw is the yellow block of the main article. We get the height with JQuery, and apply the scale factor.
1 var draw_content = function(){ 2 var content_height = $('#content').height(); 3 ctx.fillStyle = "rgb(255,255,0)"; 4 ctx.fillRect (0, 0, 100, content_height * scale_factor() ); 5 }
We set the colour manually, but could derive that from the element itself.
Drawing the comments is a bit more involved because they have top offset, and I decided to highlight comments the author has made:
1 var draw_comments = function(){ 2 $(".comment").each(function(){ 3 if (this.className.indexOf('author') != -1){ 4 ctx.fillStyle = "rgb(255, 100, 100)"; 5 } else { 6 ctx.fillStyle = "rgb(200,200,200)"; 7 } 8 ctx.fillRect(0, $(this).offset().top * scale_factor(), 100, $(this).height() * scale_factor() ); 9 }) 10 }
Adding a viewer portal
We can use the same scale factor to place a box on the canvas to represent the part of the page we are viewing. The height of the box is the height of the window multiplied by the scale factor, and the distance from the top of the canvas is the scroll offset of the window.
1 var draw_viewer = function(){ 2 ctx.fillStyle = "rgba(255,255,255,0.5)"; 3 ctx.strokeRect(0, $(window).scrollTop() * scale_factor(), 100, $(window).height() * scale_factor() ); 4 }
We need the viewer to move when we scroll, so we bind to the window scroll method:
1 $(window).scroll(function(){ draw() })
Because we have the view on the canvas itself, we have to clear the canvas first, and then redraw everything. This isn't very expensive though.
Taking the example forward
To make this more interactive, you could turn the viewer into a DOM element which has position:absolute. This allows it to be dragged, which can in turn affect the scroll position of the entire page. However, this is relatively easy to do, and can be an exercise for anyone interested.

