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
The problem is that you are hooking your onmousewheel
event on #foo
but don't realize that #foo
is only as big as the data it contain. If you make the following change (i.e. take #wrapper
instead of #foo
)
var listHold = document.getElementById('wrapper');
You'll notice that the value do get updated.
I've noticed that your jsbin example has been modified slightly and is using the wheelDelta attribute. This is why you are not able to distinguish between updating horizontally and vertically. You need to use wheelDeltaX
and wheelDeltaY
, which will wither be a value or zero, depending on whether the user scrolled vertically or horizontally.
Also, be careful using the mousewheel event, it is not standards compliant so may come back to haunt you. Might be worth having a look at the JQuery source to see how the scroll()
method implements these handlers. I would imagine there is a timer that monitors the scroll offsets of the element, which triggers synthetic events when the object scrolls. But that is a complete wild guess. Like I said, you are better off having a look at it.
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%;
}
<div id="listHolder"></div>
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'