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 scroll whether happened vertical / horizontal updating table values. But I have two problems in this
Here are problems with my code
Here is the jsbin link http://jsbin.com/oSOsIQe/2/edit
Here is the JS code, I know code is not clean but I will clean it later.
var $matrix = (function () {
function $matrix(data, holder, hidescrollbar, config) {
var header_h = config.header || "150px";
var data_h = config.header || "90px";
!data && (function () {
// Fake Data, will be removed later
data = new Array(50000);
for (var i = 0, l = data.length; i < l; i++) {
var dummy = Math.random().toString(36).substring(5);
var dum = [];
for (var j = 0; j < 26; j++) {
dum.push(dummy + i);
}
data[i] = dum;
}
}());
hidescrollbar = hidescrollbar || false;
var heightForcer = holder.appendChild(document.createElement('div'));
heightForcer.id = "heightForcer";
var view = null;
//get the height of a single item
var dimensions = (function () {
//generate a fake item and calculate dimensions of our targets
var div = document.createElement('div');
div.style.height = "auto";
div.innerHTML = "<div class='rowHeader'>fake</div><div class='rowData'>fake</div>";
holder.appendChild(div);
var output = {
row: div.firstChild.offsetHeight,
header: div.firstChild.offsetWidth,
data: div.lastChild.offsetWidth
}
holder.removeChild(div);
return output;
})();
function refreshWindow() {
//remove old view
if (view != null) {
view.innerHTML = "";
} else {
//create new view
view = holder.appendChild(document.createElement('div'));
}
var firstItem = Math.floor(holder.scrollTop / dimensions.row);
var lastItem = firstItem + Math.ceil(holder.offsetHeight / dimensions.row) + 1;
if (lastItem + 1 >= data.length) lastItem = data.length - 1;
var hfirstItem = Math.floor(holder.scrollLeft / dimensions.data);
var hlastItem = hfirstItem + Math.ceil(holder.offsetWidth / dimensions.data) + 1;
if (hlastItem + 1 >= data[firstItem].length) hlastItem = data[firstItem].length - 1;
//position view in users face
view.id = 'view';
view.style.top = (firstItem * dimensions.row) + 'px';
view.style.left = (hfirstItem * dimensions.data) + 'px';
var div;
//add the items
for (var index = firstItem; index <= lastItem; ++index) {
div = document.createElement('div');
var curData = data[index].slice(hfirstItem, hlastItem);
div.innerHTML = '<div class="rowHeader">' +
curData.join('</div><div class="rowData">') +
"</div>";
div.className = "listItem";
div.style.height = dimensions.row + "px";
view.appendChild(div);
}
console.log('viewing items ' + firstItem + ' to ' + lastItem);
}
heightForcer.style.height = (data.length * dimensions.row) + 'px';
heightForcer.style.width = (data[0].length * dimensions.data) + 'px';
if (hidescrollbar) {
//work around for non-chrome browsers, hides the scrollbar
holder.style.width = (holder.offsetWidth * 2 - view.offsetWidth) + 'px';
}
refreshWindow();
function delayingHandler() {
//wait for the scroll to finish
//setTimeout(refreshWindow, 10);
refreshWindow();
}
if (holder.addEventListener) holder.addEventListener("scroll", delayingHandler, false);
else holder.attachEvent("onscroll", delayingHandler);
}
return $matrix;
}());
new $matrix(undefined, document.getElementById('listHolder'), false, {
header: "150px",
data: "90px",
headerColumns: 2
});
Please help me on this.
Re: PLEASE HELP - Excel Horizontal Scroll Not Workingremove filters. unfreeze panes. Change from Normal view to Page Break Preview then back to Normal. Close/Re-open the application.
Horizontal scrolling can be achieved by clicking and dragging a horizontal scroll bar, swiping sideways on a desktop trackpad or trackpad mouse, pressing left and right arrow keys, or swiping sideways with one's finger on a touchscreen.
In most applications, one can scroll horizontally using a combination of holding Ctrl/Shift and using the scrollwheel.
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'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With