Skip navigation

Blog > A dynamic scrolling HTML table With miniview using Mootools JavaScript

Introduction

When developing a site, there are some rare occasions when a plain HTML table just isn't enough. Clients often ask "Can we have it scroll?", "Can we keep the row and column headings in sight?" and "Can we have a minimap with a scrollable window and a perfectly to scale tiny view of the main table that scrolls in sync with it, that the client can click or drag to view different sections?". Ok, that last one might be a bit of an exaggeration, but then that is the point of a client isn't it? To stretch your capabilities, ask for the impossible and then expect nothing less.

Luckily this tutorial will deliver all these things (!) and on the way, we can explore some of the functionality of the MooTools framework and the concept of progressive enhancement using JavaScript. So where do we start? Surprisingly, we'll start with the people who will benefit the least from your newly acquired expertise - people who somehow live with a browser that doesn't run JavaScript. These people will still need to see the table and understand its contents, as will search engines and people using screen readers or other accessibility software. So, lets start with a simple HTML table that everyone can use and understand.

View the basic table here

For the purposes of this demonstration we'll be using a very simple Gantt style project chart. Exactly the sort of thing that a miniview is useful for. So, lets add some CSS to style it up a bit.

View the style table here

As you can see by constraining it to a fixed width div, you can emulate at a very low level the scrolling capability that is required of larger tables. By having good semantically correct table structure and using CSS to style it for compatible browsers you are already using the concept of progressive enhancement to benefit more advanced users with more capable browsers without harming the underlying data which is still available for everyone to see.

Easy does it

In order to manipulate the various aspects of the table, we need to have a full understanding of the relative dimensions of both the table and the viewport into it. This requires a lot of data gathering at the top of the code which neatly wraps all the pertinent data into simple, accessible variables.

The next step is to break out the row headings into a fixed position to the left of the actual table which will allow them to stay in view whilst the main table scrolls left to right. This is where the real power of the MooTools framework comes into play. We can simply clone the main table, cut down its contents and then insert it back into the page next to the original. To afford the table some room we also shunt the original table to the right leaving enough space for the new table.

var aClone = FOriginalTable.clone(); aClone.set({'id': 'timelineleft', 'summary' : ''}); aClone.setStyle('top', (aMiniHeight + 32) + 'px'); aClone.getElement('thead').destroy(); aClone.getElements('tr').each(function(aTr){ aTr.getElements('td').each(function(aTd, aIndex) { if (aIndex > 0) aTd.destroy(); }); }); aClone.inject($$('body')[0], 'inside');

Having replicated the row headings to the left of the table we can then remove them from the original as they are no longer necessary. Easy.

$$('#calendartable tr td:first-child, #calendartable tr th:first-child').destroy();

Now to create the miniview. Again, we can clone the original table, change its id (so that the CSS can apply the minimap styling) and position it above the original table again shunting the other two tables down to allow room for it. We also quickly add a div that represents the area of the main table that is currently in view. The dimensions of all these elements are calculated using some relatively simply mathematics.

var aClone = FOriginalTable.clone(); aClone.set({'id' : 'calendartable-mini', 'summary' : ''}); aClone.setStyle('height', aMiniHeight + 'px'); aCloneRow = aClone.getElement('thead').getElement('tr').clone(); aCloneRow.getElements('th').each(function(aTh) { new Element('td', {html: ''}).replaces(aTh); }); aClone.getElement('thead').destroy(); aClone.getElements('a').set('html', ''); aCloneRow.inject(aClone.getElement('tbody').getElement('tr'), 'before'); aClone.getElements('td').setStyle('width', FMiniWidth / FNumColumns); aClone.inject('calendartable-overlay', 'after');

Obviously, all of this code relies on the MooTools framework which you can download from http://mootools.net/. There are plenty of MooTools tutorials knocking around, so I won't go into any detail as the the very basic elements of the framework as other people have already done it far better than I could.

Again, our most basic user will simply continue to see the plain html table because all of the new styling and functionality has been implemented or activated using JavaScript and CSS leaving the underlying data unchanged for anyone not using these technologies.

View the almost complete table here

Run with it

We are really getting somewhere now. We have a minimap, a permanently fixed set of row headings and a scrollable table, but we now need to build the extra navigation that the client has demanded. First we need to insert some left and right navigation arrows and attach the scrolling ability to them. As you can see this is relatively straightforward to achieve using the power of MooTools to easily create a new element and inject it into the page. The CSS attached to these elements takes care of the positioning whilst we add a left and right scroll function to both of the links.

The scrolling functions simply increment or decrement the position of the left hand edge of the viewport. This is then converted in the DoSlide function to the x position for the miniviewport and main viewport. The MooTools tween capability is then used to smoothly scroll to the new position. Simple.

View the table with scrolling arrows here

Almost there

Potentially the most difficult functionality of all still remains to be activated - the drag and drop of the minimap viewport and the click to slide functionality of the same. However, MooTools makes this a relatively straightforward process and by keeping track of the left hand edge of the minimap viewport we can easily plug this value into the slide function to move the view as required. In fact, given the rest of the code, this is a relatively painless experience.

View the finished table here

Conclusion

What started as a potential nightmare scenario has ended up being a relatively straightforward process. The power of MooTools combined with a step by step approach using the concept of progressive enhancement has resulted in a successful solution with a simple fallback for users unable to use the full power of CSS and JavaScript. For once, you may well have completely satisfied a theoretical client.

The code isn't perfect, but hopefully it is relatively readable and understandable. There are a lot of further enhancements that could be made such as:

  • Use of absolutely perfect HTML table syntax
  • Building the whole functionality into a class based implementation
  • Add a table footer to the table
  • Assigning scroll capability <- and -> to the cursor keys
  • Adjusting the width of the main table viewport and minimap so that the MooTools enhanced version occupies exactly the same width as the fallback mechanism.
  • Add vertical scrolling for really tall tables