fin-hypergrid
Version:
Canvas-based high-performance grid
123 lines (102 loc) • 4.98 kB
JavaScript
'use strict';
var bundleColumns = require('./bundle-columns');
var bundleRows = require('./bundle-rows');
/** @summary Render the grid with consolidated row OR column rects.
* @desc Paints all the cells of a grid, one column at a time.
*
* First, a background rect is drawn using the grid background color.
*
* Then, if there are any rows with their own background color _that differs from the grid background color,_ these are consolidated and the consolidated groups of row backgrounds are all drawn before iterating through cells. These row backgrounds get priority over column backgrounds.
*
* If there are no such row background rects to draw, the column rects are consolidated and drawn instead (again, before the cells). Note that these column rects are _not_ suitable for clipping overflow text from previous columns. If you have overflow text, either turn on clipping (big performance hit) or turn on one of the `truncateTextWithEllipsis` options.
*
* `try...catch` surrounds each cell paint in case a cell renderer throws an error.
* The error message is error-logged to console AND displayed in cell.
*
* Each cell to be rendered is described by a {@link CellEvent} object. For performance reasons, to avoid constantly instantiating these objects, we maintain a pool of these. When the grid shape changes, we reset their coordinates by setting {@link CellEvent#reset|reset} on each.
*
* See also the discussion of clipping in {@link Renderer#paintCellsByColumns|paintCellsByColumns}.
* @this {Renderer}
* @param {CanvasRenderingContext2D} gc
* @memberOf Renderer.prototype
*/
function paintCellsByColumnsAndRows(gc) {
var grid = this.grid,
gridProps = grid.properties,
prefillColor, rowPrefillColors, gridPrefillColor = gridProps.backgroundColor,
cellEvent,
rowBundle, rowBundles,
columnBundle, columnBundles,
visibleColumns = this.visibleColumns,
visibleRows = this.visibleRows,
c, C = visibleColumns.length,
cLast = C - 1,
r, R = visibleRows.length,
pool = this.cellEventPool,
preferredWidth,
columnClip,
// clipToGrid,
viewWidth = C ? visibleColumns[C - 1].right : 0,
viewHeight = R ? visibleRows[R - 1].bottom : 0;
gc.clearRect(0, 0, this.bounds.width, this.bounds.height);
if (!C || !R) { return; }
if (gc.alpha(gridPrefillColor) > 0) {
gc.cache.fillStyle = gridPrefillColor;
gc.fillRect(0, 0, viewWidth, viewHeight);
}
if (this.gridRenderer.reset) {
this.resetAllGridRenderers();
this.gridRenderer.reset = false;
bundleRows.call(this, false);
bundleColumns.call(this, true);
} else if (this.gridRenderer.rebundle) {
this.gridRenderer.rebundle = false;
bundleColumns.call(this);
}
rowBundles = this.rowBundles;
if (rowBundles.length) {
rowPrefillColors = this.rowPrefillColors;
for (r = rowBundles.length; r--;) {
rowBundle = rowBundles[r];
gc.clearFill(0, rowBundle.top, viewWidth, rowBundle.bottom - rowBundle.top, rowBundle.backgroundColor);
}
} else {
for (columnBundles = this.columnBundles, c = columnBundles.length; c--;) {
columnBundle = columnBundles[c];
gc.clearFill(columnBundle.left, 0, columnBundle.right - columnBundle.left, viewHeight, columnBundle.backgroundColor);
}
}
// gc.clipSave(clipToGrid, 0, 0, viewWidth, viewHeight);
// For each column...
var p = 0;
this.visibleColumns.forEachWithNeg(function(vc, c) {
cellEvent = pool[p];
vc = cellEvent.visibleColumn;
if (!rowPrefillColors) {
prefillColor = cellEvent.column.properties.backgroundColor;
}
// Optionally clip to visible portion of column to prevent text from overflowing to right.
columnClip = vc.column.properties.columnClip;
gc.clipSave(columnClip || columnClip === null && c === cLast, 0, 0, vc.right, viewHeight);
// For each row of each subgrid (of each column)...
for (preferredWidth = r = 0; r < R; r++, p++) {
if (!pool[p].disabled) {
if (rowPrefillColors) {
prefillColor = rowPrefillColors[r];
}
try {
preferredWidth = Math.max(preferredWidth, this._paintCell(gc, pool[p], prefillColor));
} catch (e) {
this.renderErrorCell(e, gc, vc, pool[p].visibleRow);
}
}
}
gc.clipRestore(columnClip);
cellEvent.column.properties.preferredWidth = Math.round(preferredWidth);
}.bind(this));
// gc.clipRestore(clipToGrid);
this.paintGridlines(gc);
}
paintCellsByColumnsAndRows.key = 'by-columns-and-rows';
paintCellsByColumnsAndRows.rebundle = true; // see rebundleGridRenderers
module.exports = paintCellsByColumnsAndRows;