:: Forum >>
scrollbar doesn't move when tabbing across grid
hi,
my horizontal scrollbar doesn't move when tabbing across the grid. has anyone any ideas?
i've tried :
var scrollbars = this.getTemplate("layout").getContent("scrollbars");
and then the following to place the scroll into the new position:
myGrid.setAction("adjustScroll", function(src){
try {
var layout = this.getLayoutTemplate();
var top = layout.getContent("top").element();
var left = layout.getContent("left").element();
var data = layout.getContent("data").element();
var scrollbars = layout.getContent("scrollbars").element();
var cell = src.element();
var scroll = data.scrollLeft;
var width = data.offsetWidth - left.offsetWidth;
var right = cell.offsetLeft + cell.offsetWidth - (this.$browser == "gecko" ? left.offsetWidth : 0);
if (right > scroll + width) {scroll = right - width}
var left = cell.offsetLeft - (this.$browser == "gecko" ? left.offsetWidth : 0);
if (!(left > scroll)) {
if(left != scroll){
scroll = left
}
}
top.scrollLeft = scroll;
data.scrollLeft = scroll;
scrollbars.scrollLeft = scroll;
alert("scroll: "+scroll)
}
catch(e){
// ignore errors
}
});
but scrollbar doesn't move!!
Daithi
Wednesday, March 2, 2005
First, the two arguments of the Grid constructor are stored for later use. The name argument is a unique name used for storing the Grid object as a property of the window object. The data argument contains information needed by the Grid including row and column headers, cell size, and more
function Grid(name, data)
{
this.name = name;
this.data = data;
var cursor = document.all ? "hand" : "pointer";
window[name] = this;
this.xOffset = 0;
this.yOffset = 0;
Now the rendering process begins. Rather than calling document.write() multiple times (which can be slow), Ive stored the HTML text in an array which will be combined into one string at the end of the rendering. First, a <table> element is added with an id that matches the name of the Grid object
// render the grid
var aStr = new Array();
aStr.push('<table border=1 cellpadding=0 cellspacing=0 id="' + name + '">');
The first row contains the column headers. Note that each column header is placed inside a <span> element inside a <th>. The reason for this will become apparent when using the init method.
aStr.push('<tr>');
aStr.push('<td> </td>');
for ( var j = 0; j < data.nCol; j++ )
{
aStr.push('<th width=' + data.nCellWidth + '><span>' +
data.colHeaders[j] + '</span></th>');
}
aStr.push('<td width=20> </td>');
aStr.push('</tr>');
For each data row, a row header is included at the front. Note: Here, each row header and data value is contained within a <span> element. On the span elements for the value cells, the overflow:hidden style is used to ensure the cells are all the same size. If any cell is allowed to expand, it will cause problems with the scroll bar rendering.
// data rows
for ( var i = 0; i < data.nRow; i++ )
{
aStr.push('<tr>');
// row header
aStr.push('<th valign=top width=' + data.nCellWidth + '><span>' +
data.rowHeaders[i] + '</span></th>');
// value cells
for ( j = 0; j < data.nCol; j++ )
aStr.push('<td><span style="overflow:hidden;width:' +
data.nCellWidth + 'px;height:' + data.nCellHeight + 'px; ' +
'text-align:center;">' + data.values[i][j] + '</span></td>');
The vertical scrollbar is added by including a <td> element at the end of the first row with colspan equal to the number of rows in the grid. There are two parts to the scrollbar; the first part is a scroll indicator, which shows which section of the source data is being viewed and the second part contains the control buttons used to modify the scroll position. In this example I have used the characters ^ and v for up and down and < and > for left and right.
These two parts are overlaid, one on top of the other using the position:absolute style. The button part is above the indicator so the buttons may be clicked.
==============
Use JavaScript to Create a Scrolling Grid
The scroll indicator is displayed using a table with three rows, for above, visible and below. The cell heights are used here to give the impression of a scroll bar. Note that it is not valid to specify a cell height of zero, so instead we use a value of one.
// add the vertical scroll bar
if ( i == 0 )
{
aStr.push('<td rowspan=' + data.nRow + ' valign=top>');
aStr.push('<div style="position:relative;height:' +
nHeight + 'px;width:20px;">');
// add the scroll indicator
var nHeight = data.nRow * data.nCellHeight + (data.nRow-1) * 2;
var nStartHeight = 1;
var nBarHeight = Math.floor(nHeight * data.nRow / data.rowHeaders.length);
var nEndHeight = nHeight - nStartHeight - nBarHeight;
aStr.push('<div style="position:absolute;height=120px;">');
aStr.push('<table width=20 height=' + nHeight +
' border=0 cellpadding=0 cellspacing=0>');
aStr.push('<tr><td height=1><div></div></td></tr>');
aStr.push('<tr><td height=' + nBarHeight +
' bgcolor="#33cc33" height=20><div></div></td></tr>');
aStr.push('<tr><td height=' + nEndHeight + '><div></div></td></tr>');
aStr.push('</table>');
aStr.push('</div>');
// add the scroll buttons
aStr.push('<div style="position:absolute;height=' +
nHeight + 'px;width=20px;">');
aStr.push('<table width=20 height=' + nHeight +
' border=0 cellpadding=0 cellspacing=0>');
aStr.push('<tr><td width=' + nHeight/2 + ' valign=top align=center>' +
'<div style="cursor:' + cursor + ';" ' +
'onclick="window.' + name + '.scroll(0,-1);">^</div></td></tr>');
aStr.push('<tr><td width=' + nHeight/2 + ' valign=bottom align=center>' +
'<div style="cursor:' + cursor + ';" ' +
'onclick="window.' + name + '.scroll(0,1);">v</div></td></tr>');
aStr.push('</table>');
aStr.push('</div>');
aStr.push('</div>');
aStr.push('</td>');
}
At the end of each row, we close with a </tr>.
strHTML.push('</tr>');
}
The horizontal scrollbar is added in much the same way as the vertical one:
// add the horizontal scroll bar
aStr.push('<tr>');
aStr.push('<td> </td>');
aStr.push('<td colspan=' + this.data.nCol + '>');
aStr.push('<div style="position:relative;width=' + nWidth + 'px;height=20px;">');
// the scroll indicator part
var nWidth = this.data.nCol * this.data.nCellWidth + (this.data.nCol-1) * 2;
var nStartWidth = 1;
var nBarWidth = Math.floor(nWidth * this.data.nCol /
this.data.colHeaders.length);
var nEndWidth = nWidth - nStartWidth - nBarWidth;
aStr.push('<div style="position:absolute;width=' +
nWidth + 'px;left:0px;top:0px">');
aStr.push('<table width=' + nWidth + ' border=0 cellpadding=0 cellspacing=0>');
aStr.push('<tr>');
aStr.push('<td width=1><div></div></td>');
aStr.push('<td width=' + nBarWidth + ' bgcolor="#33cc33" ' +
'height=20><div></div></td>');
aStr.push('<td width=' + nEndWidth + '><div></div></td>');
aStr.push('</tr>');
aStr.push('</table>');
aStr.push('</div>');
// the scroll buttons
aStr.push('<div style="position:absolute;width=' + nWidth + 'px;' +
'left:0px;top:0px">');
aStr.push('<table width=' + nWidth + ' border=0 cellpadding=0 cellspacing=0>');
aStr.push('<tr>');
aStr.push('<td width=' + nWidth/2 + ' align=left><div style="cursor:' + cursor +
';width:20px;" onclick="window.' + this.name + '.scroll(-1,0);">' +
'<</div></td>');
aStr.push('<td width=' + nWidth/2 + ' align=right><div style="cursor:' + cursor +
';width:20px;" onclick="window.' + this.name + '.scroll(1,0);">' +
'></div></td>');
aStr.push('</tr>');
aStr.push('</table>');
aStr.push('</div>');
aStr.push(' ');
aStr.push('</div>');
aStr.push('</td>');
aStr.push('<td> </td>');
aStr.push('</tr>');
Finally the grid <table> is closed and the array is written to the document.
// finally close off the table
aStr.push('</table>');
// write HTML to document.
document.write(aStr.join(''));
}
With the constructor call complete, the Grid should now be drawn on the browser page and look something like Fig 2 shown above. All that is left now is to handle the scroll button clicks.
If you look at how the scroll buttons were defined above, youll notice that they each contained an onclick handler something like the following:
window.theGrid.scroll(1,0);
theGrid is the name of the Grid object passed into the constructor.
This code retrieves the Grid object from the window object and calls a scroll method passing in a couple of values that specify how much to scroll either horizontally or vertically. After the x and y offsets have been adjusted appropriately, the scroll method calls a fill method to update the Grid.
Grid.prototype.scroll = function(x,y)
{
this.xOffset += x;
if ( this.xOffset < 0 )
this.xOffset = 0;
if ( this.xOffset > this.data.colHeaders.length - this.data.nCol )
this.xOffset = this.data.colHeaders.length - this.data.nCol;
this.yOffset += y;
if ( this.yOffset < 0 )
this.yOffset = 0;
if ( this.yOffset > this.data.rowHeaders.length - this.data.nRow )
this.yOffset = this.data.rowHeaders.length - this.data.nRow;
this.fill();
}
The fill method loops through the row and column header arrays and the two-dimensional value array, setting the values appropriately. The sizes of the vertical and horizontal scroll indicator sections are calculated and adjusted as well.
Grid.prototype.fill = function()
{
this.init();
// row headers
for ( var i = 0; i < this.data.nRow; i++ )
this.aRowSpan[i].innerHTML = this.data.rowHeaders[i + this.yOffset];
// column headers
for ( var j = 0; j < this.data.nCol; j++ )
this.aColSpan[j].innerHTML = this.data.colHeaders[j + this.xOffset];
// values
for ( i = 0; i < this.data.nRow; i++ )
for ( j = 0; j < this.data.nCol; j++ )
this.aCellSpan[i][j].innerHTML =
this.data.values[i + this.yOffset][j + this.xOffset];
// vertical scrollbar
var nHeight = this.data.nRow * this.data.nCellHeight + (this.data.nRow-1) * 2;
var nStartHeight =
Math.floor(nHeight * this.yOffset / this.data.rowHeaders.length);
if ( nStartHeight == 0 ) nStartHeight++;
var nBarHeight =
Math.floor(nHeight * this.data.nRow / this.data.rowHeaders.length);
var nEndHeight = nHeight - nStartHeight - nBarHeight;
if ( nEndHeight == 0 ) nStartHeight--, nEndHeight++;
this.aVerticalTD[0].height = nStartHeight;
this.aVerticalTD[1].height = nBarHeight;
this.aVerticalTD[2].height = nEndHeight;
// horizontal scrollbar
var nWidth = this.data.nCol * this.data.nCellWidth + (this.data.nCol-1) * 2;
var nStartWidth =
Math.floor(nWidth * this.xOffset / this.data.colHeaders.length);
if ( nStartWidth == 0 ) nStartWidth++;
var nBarWidth =
Math.floor(nWidth * this.data.nCol / this.data.colHeaders.length);
var nEndWidth = nWidth - nStartWidth - nBarWidth;
if ( nEndWidth == 0 ) nEndWidth++, nStartWidth--;
this.aHorizontalTD[0].width = nStartWidth;
this.aHorizontalTD[1].width = nBarWidth;
this.aHorizontalTD[2].width = nEndWidth;
}
===================
An init method is used to locate the row/column header and value <span> elements defined during the rendering phase. This is easily done thanks to the document.getElementsByTagName() method. This method gathers all the elements of a given tag name and returns them in order in an array. The column headers come first, then each row with a row header at the beginning of each row (this follows the way in which they were rendered).
A similar technique is used to find the <td> elements used for the scroll indicators; first the <div> elements are enumerated, the second one contains the vertical scroll indicator and the tenth contains the horizontal one. These <span> and <td> elements are stored in arrays held by the Grid object so they may be used by the fill method.
Grid.prototype.init = function()
{
// if already initialized, return
if ( this.oTable ) return;
this.oTable = document.getElementById(this.name);
// get all <span> elements within the table
var aSpan = this.oTable.getElementsByTagName('span');
var n = 0;
// the first few are all column headers
this.aColSpan = new Array;
for ( var j = 0; j < this.data.nCol; j++ )
this.aColSpan.push(aSpan[n++]);
// the remainder are row headers and cells
this.aRowSpan = new Array;
this.aCellSpan = new Array;
for ( var i = 0; i < this.data.nRow; i++ )
{
this.aRowSpan.push(aSpan[n++]);
this.aCellSpan.push(new Array());
for ( j = 0; j < this.data.nCol; j++ )
this.aCellSpan[i].push(aSpan[n++]);
}
// get all the <div> elements
var aDiv = this.oTable.getElementsByTagName('div');
// the vertical scroll is in aDiv[1]
this.aVerticalTD = aDiv[1].getElementsByTagName('td');
// the horizontal scroll is in aDiv[9]
this.aHorizontalTD = aDiv[9].getElementsByTagName('td');
}
All that is left now is to demonstrate how the Grid class is used. In fact, all that is required is to instantiate a Grid object wherever it is required within the <body> of the web page, supplying a unique name and a data object with the required properties defined.
<script>
var data =
{
nCol:6,
nRow:10,
nCellWidth:70,
nCellHeight:20,
colHeaders:["USD", "EUR","GBP", ...],
rowHeaders:["USD", "EUR","GBP", ...],
values:[["-",1.1,1.8,...],[...], ...]
};
new Grid('theGrid', data);
</script>
ManojBellan,OOTY,Niligiri's,INDIA
Tuesday, December 19, 2006
This topic is archived.
Back to support forum
Forum search