danielgindi/jquery.dgtable

Dynamic row height in Virtual mode

sirzento opened this issue · 1 comments

I Edit some parts of your Code and got it to work on your example page. It is not perfekt but it works.
You also Need to remove "white-space: nowrap;" from ".dgtable-cell > div".

Bugs:

  • After a specific amount of rows (~160k or Top value of 1.67773e+07) Google Chrome doesnt render the rows anymore (But they are still there in the DOM object and correct in the element inspector).
    This bug only happens in my project :/
    Updating Chrome to 69.0.3497.81 fixed this Problem but after top value 1.677715e+07px the border-bottom of the rows is invisible. This goes for your examplepage too. Apparently this also happens in the original Version.

  • On Microfot Edge if the table has more that 100k rows (100k works and 200k doesnt) the virtual table heightdoesnt work properly (The virtual table scrollbar is very big and gets smaller if you scroll to the bottom).
    This happens in my project and in your example page exactly after Top value 10737418px is exceed.

Tested with:

  • Google Chrome 68.0.3440.106 64-Bit
  • Microsoft Edge 42.17134.1.0

Basically in the code the length of the content of the column "address" is compared with a value, in which case 15 letters, and then counted how many line breaks must be made and the value is taken times 25px (25px is about one line height) This is in the code as follows: "var textLinesHeigth = Math.floor(element.address.length / 15) * 25;
". To do this not only for the column "Address" but for all columns you just have to run a ForEach loop through all columns and just remember the largest value.

The position of a row in the table is no longer simply calculated with the number of rows times the fixed row height, but the position of each row is stored in a large array.

I only changed 2 functions and the first/last Visible calculation.
(Comments in bad english incoming)

        /**
	 * Calculate virtual table height for scrollbar
	 * @private
	 * @returns {DGTable} self
	 */
	DGTable.prototype._calculateVirtualHeight = function () {
	    var p = this.p;

	    if (p.tbody) {
	       
			var rows = p.filteredRows || p.rows;
			var counter = 0;
			p.topIndex = [];
			
			//fills the topIndex with values.
			rows.forEach(function(element){
			var textLinesHeigth = Math.floor(element.address.length / 15) * 25;
					if(textLinesHeigth < 25)
						textLinesHeigth = 25;
			if(counter > 0){
				//combines the heigt value and all other values to get its start position.
				p.topIndex.push(textLinesHeigth + p.topIndex[counter - 1]);
			}else{		
				//only for the first row.
				p.topIndex.push(textLinesHeigth);
			}
			counter++;
			});
			
			//virtual heigth is 
	        p.tbody.style.height = p.topIndex[p.topIndex.length - 1] + 'px';
	    }
	    return this;
	};

And:

/**
	 * Render rows
	 * @private
	 * @param {Number} first first row to render
	 * @param {Number} last last row to render
	 * @returns {DocumentFragment} fragment containing all rendered rows
	 */
	DGTable.prototype.renderRows = function (first, last) {
	    for (var that = this, o = that.o, p = that.p, tableClassName = o.tableClassName, rowClassName = tableClassName + '-row', cellClassName = tableClassName + '-cell', rows = p.filteredRows || p.rows, isDataFiltered = !!p.filteredRows, allowCellPreview = o.allowCellPreview, visibleColumns = p.visibleColumns, isVirtual = o.virtualTable, virtualRowHeightFirst = p.virtualRowHeightFirst, virtualRowHeight = p.virtualRowHeight, top, physicalRowIndex, colCount = visibleColumns.length, colIndex = 0, column; colIndex < colCount; colIndex++) {
	        column = visibleColumns[colIndex];
	        column._finalWidth = column.actualWidthConsideringScrollbarWidth || column.actualWidth;
	    }
			

	    for (var bodyFragment = document.createDocumentFragment(), isRtl = this._isTableRtl(), virtualRowXAttr = isRtl ? 'right' : 'left', i = first, rowCount = rows.length, rowData, row, cell, cellInner, content; i < rowCount && i <= last; i++) {

	        rowData = rows[i];
	        physicalRowIndex = isDataFiltered ? rowData['__i'] : i;

	        row = createElement('div');
	        row.className = rowClassName;
	        row['rowIndex'] = i;
	        row['physicalRowIndex'] = physicalRowIndex;
			
			//calculate the row heigth by column 'address'. At 15 chars a new line with 25px heigth will apeare.
			//'Address' was the biggest text in my test. To check for every column, just foreach it and replace 'rowData.address.length'.
			var textLinesHeigth = Math.floor(rowData.address.length / 15) * 25;
					if(textLinesHeigth < 25)
						textLinesHeigth = 25;

	        for (colIndex = 0; colIndex < colCount; colIndex++) {
	            column = visibleColumns[colIndex];
	            cell = createElement('div');
	            cell['columnName'] = column.name;
	            cell.setAttribute('data-column', column.name);
	            cell.className = cellClassName;
	            cell.style.width = column._finalWidth + 'px';
	            if (column.cellClasses) cell.className += ' ' + column.cellClasses;
	            if (allowCellPreview) {
	                p._bindCellHoverIn(cell);
	            }
	            cellInner = cell.appendChild(createElement('div'));

	            cellInner.innerHTML = this._getHtmlForCell(rowData, column);
				
				//All cells get the height of the biggest height minus 8px from the table padding.
				cell.style.height = textLinesHeigth - 8 + "px";
	            row.appendChild(cell);
	        }

	        if (isVirtual) {
				//top gets the value of the line i in topIndex.
	            top = i > 0 ? p.topIndex[i - 1] : 0;
	            row.style.position = 'absolute';
	            row.style[virtualRowXAttr] = 0;
	            row.style.top = top + 'px';
				row.style.height = textLinesHeigth + "px";
	        }

	        bodyFragment.appendChild(row);

	        that.trigger('rowcreate', i, physicalRowIndex, row, rowData);
	    }
	    return bodyFragment;
	};

The calculation for last/first Visible:

rowCount = (p.filteredRows || p.rows).length;
			
			var scrollTop = p.table.scrollTop;
			var firstVisible = 0;
			var lastVisible = 0;

			if(p.topIndex.length != 0)
			for(var i = 0; firstVisible == 0 || lastVisible == 0; i++){
				if(firstVisible == 0 && scrollTop - p.topIndex[0] <= p.topIndex[i]){
					firstVisible = i - o.rowsBufferSize;
				}
				if(lastVisible == 0 && (scrollTop - p.topIndex[0] + p.visibleHeight) <= p.topIndex[i]){
					lastVisible = i + o.rowsBufferSize;
				}
                                if(lastVisible == 0 && i > p.topIndex.length){
					lastVisible = p.topIndex.length - 1;
				}
			}

Variable row height is supported in 0.6.x!