I have a big array and I need to render it into a table. Instead of rendering all items I am rendering only few items horizontally and vertically. Then on scroll based on mouse
SOLUTION, an conceptual extension to my answer to a similar question
CODE
function matrix(data, holder, config) {
'use strict';
//copy the config, substituting defaults
config = {
cellWidth : (config && config.cellWidth) || 150,
rowHeight : (config && config.rowHeight) || 22,
};
if (!data) {
//create 50000x26 array for data
data = (function (length, depth) {
var output = new Array(length);
var startAt;
for (var index = 0; index < length; ++index) {
//var startAt = Math.random().toString(36).substring(5);
var startAt = index + ':';
output[index] = new Array(depth);
for (var index2 = 0; index2 < depth; ++index2)
output[index][index2] = startAt + index2;
}
return output;
})(50000, 26);
}
//guard against 0 length arrays
if (data.length < 1 || data[0].length < 1)
return;
var areaForcer = holder.appendChild(holder.ownerDocument.createElement('div'));
var view = null;
function refreshWindow() {
//remove old view
if (view != null)
view.innerHTML = "";
//create new view
else
view = holder.appendChild(holder.ownerDocument.createElement('div'));
var firstRow = Math.floor(holder.scrollTop / config.rowHeight);
var lastRow = firstRow + Math.ceil(holder.offsetHeight / config.rowHeight) + 1;
if (lastRow + 2 > data.length)
lastRow = data.length - 1;
var firstColumn = Math.floor(holder.scrollLeft / config.cellWidth);
var lastColumn = firstColumn + Math.ceil(holder.offsetWidth / config.cellWidth) + 1;
if (lastColumn + 2 > data[0].length)
lastColumn = data[0].length - 1;
//position view in users face
view.id = 'view';
view.style.top = (firstRow * config.rowHeight) + 'px';
view.style.left = (firstColumn * config.cellWidth) + 'px';
var row;
var cell;
//add the rows
for (var index = firstRow; index <= lastRow; ++index) {
row = view.ownerDocument.createElement('div');
row.style.height = config.rowHeight - 2 + 'px';
view.appendChild(row);
//add the cells
for (var index2 = firstColumn; index2 <= lastColumn; ++index2) {
cell = row.ownerDocument.createElement('div');
cell.className = 'listItem';
cell.innerHTML = data[index][index2];
cell.style.width = config.cellWidth - 2 + 'px';
row.appendChild(cell);
}
}
console.log('viewing items [' + firstRow + ':' + lastRow + '][' + firstColumn + ':' + lastColumn + ']');
}
areaForcer.style.height = (data.length * config.rowHeight) + 'px';
areaForcer.style.width = (data[0].length * config.cellWidth) + 'px';
refreshWindow();
function delayingHandler() {
//wait for the scroll to finish
setTimeout(refreshWindow, 10);
}
if (holder.addEventListener)
holder.addEventListener('scroll', delayingHandler, false);
else
holder.attachEvent('onscroll', delayingHandler);
}
matrix(null, document.getElementById('listHolder'), false);
html, body {
width:100%;
height:100%;
padding:0;
margin:0
}
body{
overflow:hidden;
}
.listItem {
border : 1px solid gray;
margin : 1px 0px;
display : inline-block;
}
#listHolder {
position:relative;
height:100%;
width:100%;
background-color:#CCC;
box-sizing:border-box;
overflow:auto;
}
#view {
position:absolute;
}
#view, #view * {
overflow : hidden;
white-space : nowrap;
}
#view > div {
width : 100%;
}
Just some things to clean up your code:
you're not using the object in an OO fashion, no need for new/use the function as a constructor (and if you are going to, start it with a capital)
in this day and age the compiler can do a lot of things for us, there's no reason to use names like 'i' or 'j' where 'index' is much more self explanatory, and the if statement was made for what you used the and operator for (!data && /*set data*/
, use if (!data) /*set data*/
)
don't employ anonymous, call-once functions where they're not required, they need to be recompiled each time the parent function runs
declare variables outside of loops
don't use random() (in this case) unless the code is working, makes it harder to see whats going on
personal preference send null to a function instead of undefined and don't name a function $matrix when matrix is just as apt use comments!
personal preference unless you know what you're doing, ++x is exactly what you need and x++ is a minor waste of resources
because you're using horizontal scroll, forget about hiding the scrollbar
start out simple and don't attempt to get the height, just force one. things like detecting height are niceties reserved for working solutions
always use proper indentation, even if the if statement can be written on one line. Doesn't matter about your personal preference because you're posting the code online expecting other people to help you
when you edit code make sure you update the semantics. E.g. the element called 'heightForcer' now manipulates the width aswell, obviate that by calling it 'areaForcer'