Email This Post Email This Post Print This Post Print This Post

Floating Table Titles

Tue, Jul 29, 2008 – 4:15 pm

Table Titles Float to stay in view
Tested to work in Firefox 3, Internet Explorer 7, and Safari 3.1

You will never loose sight of a tables column titles as long as the table is visible on the screen !

Click to see Example

Invisibly in the background this script will take your tables exsting titles and “fix” them so as you scroll down the page they will always remain in view.

To use the script just include the TableFloaterTitle.js file in the head of your document.


<script src=”TableFloaterTitle.js”></script>


To make the tables whoose titles you want to float just give the table a class of “FloatTitle”


<table class="FloatTitle">
  <thead>
    <tr bgcolor="#FFCC33;"><td>Title #1</td>...</tr>
  </thead>
  <tbody>
    <tr><td>Stuff</td>.../tr>
    <tr><td>Stuff</td>...</tr>
    <tr><td>Stuff</td>...</tr>
  </tbody>  

Currently tested to work in Firefox 3, IE 7, and Safari 3.1.2

Note: For now the table titles must be inside a THEAD tag

Another approach to making a tables headings and titles remain in view can be found here:
http://stansight.com/WordPress/2008/07/03/fixed-table-head/

The Code - TableFloaterTitle.js

// *****************************************************************************
// ** TableFloaterTitle.js
// **
// ** Unobtrusive JavaScript function which will keep the titles of a table on
// ** screen as the user scrolls down.  The titles will 'float' keeping in view
// ** as long as any part of the table remains in view.
// **
// ** Author: Stan Slaughter
// ** Web: http://www.StanSight.Com/
// *****************************************************************************

  //////////////////////////////////////////////////////////////////////////////
  // startFloatTitle - Start tables floating
  //
  //  This function will scan the page looking for every "table" on it.
  //  Any table which has a class of "FloatTitle" will have its ID value
  //  passed on to the function for the actual float process
  //////////////////////////////////////////////////////////////////////////////

  function startFloatTitle() {

    var cnt=0;
    var allTableIDs = new Array();
    allTables = document.getElementsByTagName("table");

    // Scan page for all tables with a class of "FloatTitle"
    for (i=0;i<allTables.length; i++) {
      if (allTables[i].className == "FloatTitle") {

        // Get the ID. If no ID exists then assign one
        tableID = allTables[i].id;
        if ( tableID == "") {
          tableID = "tmpFloatTitleTableId" + cnt;
          allTables[i].id = tableID;
        } 

        // Save ID's
        allTableIDs[cnt] = tableID;
        cnt++;
      }
    }

    // Start floating the tables title
    for (i=0;i<allTableIDs.length; i++) {
      floatTitle(allTableIDs[i],i);
    }
  }

  //////////////////////////////////////////////////////////////////////////////
  // floatTitle - Start the float process
  //  @param tableID - ID of table that floating title will be created for
  //  @param cnt - Number representing table - for tracking seperate float events
  //
  //  This function calls the functions which create the floating title and
  //  start the floating process
  //////////////////////////////////////////////////////////////////////////////

  var floatTitleTimer = new Array();
  function floatTitle(tableID,cnt) {

    // Stop any old Loops
    if (typeof(floatTitleTimer[cnt])== 'undefined') floatTitleTimer[cnt] = 0;
    clearTimeout(floatTitleTimer[cnt]);

    // Create title object then start float loop
    titleID = createTitleObj(tableID);
    floatTitleLoop(tableID,titleID,cnt);

  }

  //////////////////////////////////////////////////////////////////////////////
  // createTitleObj - Create the floating object for this table
  //  @param tableID - ID of table that floating title will be created for
  //  @return titleWrapperID - ID of div which contains a copy of tables THEAD
  //
  //  Clone the THEAD from the table, create a new table to place it in then
  //  create a DIV wrapper to place it in. The ID for the DIV is returned to
  //  the calling function so it can be used to position the object in the
  //  floating function.
  //////////////////////////////////////////////////////////////////////////////

  function createTitleObj (tableID) {

    var titleWrapperID = tableID + "Title";
    var titleTableID = tableID + "TitleTable";

    // If Title has not been created yet
    if (document.getElementById(titleWrapperID)==null) {

      // "clone" the Table's thead
      tableObj = document.getElementById(tableID);
      clonedtHead=tableObj.tHead.cloneNode(true);

      // Create wrapper div
      titleWrapperObj = document.createElement("div");
      titleWrapperObj.setAttribute("id", titleWrapperID);

      // Create the Title table
      TitleTable = document.createElement("table");
      TitleTable.setAttribute("id", titleTableID);

      // Append Cloned thead to the Title table
      TitleTable.appendChild( clonedtHead );

      // Append table to div container
      titleWrapperObj.appendChild(TitleTable);

      // Insert wrapper div into the DOM before Table
      parentDiv = tableObj.parentNode;
      parentDiv.insertBefore(titleWrapperObj, tableObj);

      // Initially position container
      titleWrapperObj.style.position="absolute";
      titleWrapperObj.style.top = "0px";
      titleWrapperObj.style.zIndex="1";
    }

    tableObj = document.getElementById(tableID);
    titleTableObj = document.getElementById(titleTableID);

    // Set Title width to be the same as Table
    titleWrapperObj = document.getElementById(titleWrapperID);
    titleWrapperObj.style.width = tableObj.offsetWidth + 'px';

    // Set widths of Title TD's to same as Table TD's
    tableCells = tableObj.tHead.rows[0].cells;
    titleTableCells = titleTableObj.tHead.rows[0].cells;

    for (var i=0; i != tableCells.length; i++) {
      titleTableCells[i].style.width = (tableCells[i].clientWidth)+ 'px';
      titleTableCells[i].style.cursor = 'normal';
    }

    return titleWrapperID;
  }

  //////////////////////////////////////////////////////////////////////////////
  // floatTitleLoop - Float the titles up and down the table as the page scrolls
  //  @param tableID - ID of table that wants floating title
  //  @param titleID - ID of div that will float (contains copy of tableID's THEAD)
  //  @param cnt - Number representing table - for tracking seperate float events
  //
  //  Keep the title object in view as the table postion changes as a user
  //  scrolls up and down in the window
  //////////////////////////////////////////////////////////////////////////////

  function floatTitleLoop(tableID,titleID,cnt) {

    // If Table and Title objects exist
    if (document.getElementById(tableID) !=null && document.getElementById(titleID) !=null) {

      // Set value to be number of pixels from screen top that you wish
      // scrolling to start at. 0=top, 10=10 pixels down from top, etc..
      // Useful for those who happen to have top screen banners
      var	startOffsetTop = 0;

      // Get start and stop float positions from table
      var tableObj = document.getElementById(tableID);
      var tablePos = FindPosition(tableObj);
      var startTop = tablePos[1] - startOffsetTop;
      var endTop = startTop + tableObj.clientHeight;		

      // Get new positon of body scroll top and keep it in bounds
      var newTop =(document.documentElement.scrollTop>0) ? document.documentElement.scrollTop : document.body.scrollTop;
      if (newTop < startTop) newTop = startTop;
      if (newTop > endTop) newTop = endTop;

      // Move the title to new postion
      var titleObj = document.getElementById(titleID);
      if (newTop > startTop && newTop < endTop) {

        // Display "Title" if it is not all ready being displayed
        if (titleObj.style.display != 'block') titleObj.style.display='block';

        // Apply offset to get newTop position
        newTop = newTop + startOffsetTop;

        // Apply Ease-In effect
        easeInWanted=true;
        if (easeInWanted) {

          // Get current location and get the difference from where it's
          // at to where you want it to go
          oldTop = parseInt(titleObj.style.top);
          topDiff=newTop-oldTop; 

          // Calaculate how far you want to move it - then set that to new postion
          moveTop=0;
          if ( (topDiff < (-1) ) || (topDiff > (1) ) ) { moveTop=Math.round(topDiff/3);}
          newTop = oldTop + moveTop;
        }

      	// Move to new top position
      	if (newTop < 0) newTop = 0;
      	titleObj.style.top = newTop + "px";
      } else {
        // Else hide "Title" if it is not all ready hidden
        if (titleObj.style.display != 'none') {
          titleObj.style.display='none';
          titleObj.style.top = "0px";
          titleObj.style.zIndex="1";
        }
      }

    }

    // Execute this function again in 40 milliseconds (thousandths of a second)
    cmd = "floatTitleLoop('" + tableID + "','" + titleID + "','" + cnt + "')";
    floatTitleTimer[cnt] = window.setTimeout(cmd, 40); 

  }

  //////////////////////////////////////////////////////////////////////////////
  // FindPosition - find the Top and Left postion of an object on the page
  //  @param obj - object of element whose position needs to be found
  //  @return array - Array whoose first eleemnt is the left postion and whoose
  //                  second is the top position
  //////////////////////////////////////////////////////////////////////////////

  function FindPosition(obj) {
    // Figure out where the obj object is in the page by adding
    // up all the offsets for all the containing parent objects
    if (obj == null) return [0,0];

    // Assign the obj object to a temp variable
    tmpObj = obj;

    // Get the offsets for the current object
    var obj_left = tmpObj.offsetLeft;
    var obj_top = tmpObj.offsetTop;

    // If the current object has a parent (ie contained in a table, div, etc..)
    if (tmpObj.offsetParent) {

      // Loop through all the parents and add up their offsets
      // The while loop will end when no more parents exist and a null is returned
      while (tmpObj = tmpObj.offsetParent) {
      	obj_left += tmpObj.offsetLeft;
      	obj_top += tmpObj.offsetTop;
      }
    }
    return [obj_left , obj_top];
  }

  //////////////////////////////////////////////////////////////////////////////
  // Start floating titles after window finishes loading
  ////////////////////////////////////////////////////////////////////////////// 

  window.onload = startFloatTitle;

  //////////////////////////////////////////////////////////////////////////////
  // Start floating titles when window is resized
  ////////////////////////////////////////////////////////////////////////////// 

  window.onresize = startFloatTitle;
  1. 3 Responses to “Floating Table Titles”

  2. nice, but seems to work only in HTML 4.01 Transitional :(

    By auroqn on Aug 12, 2008

  3. I did not think to check it under strict. (my editors default setting is transitional).

    The problem was simple to fix. I had used document.body instead of document.documentElement to get the scrollTop postion.

    I changed it so it should work in either strict or transitional mode now:

    Strict Mode example: http://www.stansight.com/TableFloaterTitle2.html

    By Stan Slaughter on Aug 13, 2008

  1. 1 Trackback(s)

  2. Aug 7, 2008: StanSight » Blog Archive » Fixed Table Head

Post a Comment

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word