Class: Renderer

Renderer

new Renderer()

fin-hypergrid-renderer is the canvas enabled top level sub component that handles the renderering of the Grid.

It relies on two other external subprojects

  1. fin-canvas: a wrapper to provide a simpler interface to the HTML5 canvas component
  2. rectangular: a small npm module providing Point and Rectangle objects

The fin-hypergrid-renderer is in a unique position to provide critical functionality to the fin-hypergrid in a hightly performant manner. Because it MUST iterate over all the visible cells it can store various bits of information that can be encapsulated as a service for consumption by the fin-hypergrid component.

Instances of this object have basically four main functions.

  1. render fixed row headers
  2. render fixed col headers
  3. render main data cells
  4. render grid lines

Same parameters as initialize, which is called by this constructor.

Members

properties

CAUTION: Keep in place! Used by Canvas.

Methods

getBoundsOfCell(x, yopt) → {Rectangle}

Parameters:
Name Type Attributes Description
x CellEvent | number

CellEvent object or grid column coordinate.

y number <optional>

Grid row coordinate. Omit if xOrCellEvent is a CellEvent.

Returns:

Bounding rect of cell with the given coordinates.

Type
Rectangle

getColumnFromPixelX(pixelX) → {number}

answer the column index under the coordinate at pixelX

Parameters:
Name Type Description
pixelX number

The horizontal coordinate.

Returns:

The column index under the coordinate at pixelX.

Type
number

getFinalVisibleColumnBoundary() → {number}

Returns:

The width x coordinate of the last rendered column

Type
number

getGridCellFromMousePoint(point) → {Object}

Answer specific data cell coordinates given mouse coordinates in pixels.

Parameters:
Name Type Description
point Point
Returns:

Cell coordinates

Type
Object

getPageDownRow() → {number}

Returns:

The row to goto for a page down.

Type
number

getPageUpRow() → {number}

Returns:

The row to go to for a page up.

Type
number

getRenderedHeight() → {number}

Returns:

The rendered row height at index

Type
number

getRenderedWidth() → {number}

Returns:

The rendered column width at index

Type
number

getScrollLeft() → {number}

Returns:

Current horizontal scroll value.

Type
number

getScrollTop() → {number}

Returns:

Current vertical scroll value.

Type
number

getVisibleColumn(columnIndex) → {object|undefined}

Find a visible column object.

Requested column may not be visible due to being scrolled out of view.

Parameters:
Name Type Description
columnIndex number

The grid column index.

Returns:

The given column if visible or undefined if not.

Type
object | undefined

getVisibleColumnsCount() → {number}

Returns:

Number of columns we just rendered.

Type
number

getVisibleDataColumn(columnIndex) → {object|undefined}

Find a visible column object.

Requested column may not be visible due to being scrolled out of view or if the column is inactive.

Parameters:
Name Type Description
columnIndex number

The grid column index.

Returns:

The given column if visible or undefined if not.

Type
object | undefined

getVisibleDataRow(rowIndex, subgridopt) → {object|undefined}

Find a visible row object.

Requested row may not be visible due to being scrolled out of view.

Parameters:
Name Type Attributes Default Description
rowIndex number

The data row index within the given subgrid.

subgrid DataModel <optional>
this.behavior.subgrids.data
Returns:

The given row if visible or undefined if not.

Type
object | undefined

getVisibleRow(rowIndex) → {object|undefined}

Find a visible row object.

Requested row may not be visible due to being outside the bounds of the rendered grid.

Parameters:
Name Type Description
rowIndex number

The grid row index.

Returns:

The given row if visible or undefined if not.

Type
object | undefined

getVisibleRowsCount() → {number}

Returns:

Answer how many rows we rendered

Type
number

initialize()

Constructor logic

This method will be called upon instantiation of this class or of any class that extends from this class.

All initialize() methods in the inheritance chain are called, in turn, each with the same parameters that were passed to the constructor, beginning with that of the most "senior" class through that of the class of the new instance.

isColumnVisible(columnIndex) → {boolean}

Determines if a column is visible.

Requested column may not be visible due to being scrolled out of view.

Parameters:
Name Type Description
columnIndex number

the column index

Returns:

The given column is visible.

Type
boolean

isDataColumnVisible(columnIndex) → {boolean}

Determines if a column is visible.

Requested column may not be visible due to being scrolled out of view or if the column is inactive.

Parameters:
Name Type Description
columnIndex number

the column index

Returns:

The given column is visible.

Type
boolean

isDataRowVisible(rowIndex, subgridopt) → {boolean}

Determines visibility of a row.

Requested row may not be visible due to being scrolled out of view.

Parameters:
Name Type Attributes Default Description
rowIndex number

The data row index.

subgrid DataModel <optional>
this.behavior.subgrids.data
Returns:

The given row is visible.

Type
boolean

isDraggingColumn() → {boolean}

Returns:

User is currently dragging a column for reordering.

Type
boolean

isLastColumnVisible() → {boolean}

Returns:

The last col was rendered (is visible)

Type
boolean

isRowVisible(rowIndex) → {boolean}

Determines visibility of a row.

Requested row may not be visible due to being outside the bounds of the rendered grid.

Parameters:
Name Type Description
rowIndex number

The grid row index.

Returns:

The given row is visible.

Type
boolean

isSelected(x, y) → {boolean}

Determines if a cell is selected.

Parameters:
Name Type Description
x number

the x cell coordinate

y number

the y cell coordinate*

Returns:

The given cell is fully visible.

Type
boolean

paint(gc)

Notify the fin-hypergrid every time we've repainted.

This is the entry point from fin-canvas.

Parameters:
Name Type Description
gc CanvasRenderingContext2D

paintCellsAsNeeded(gc)

Render the grid only as needed ("partial render").

Paints all the cells of a grid, one column at a time, but only as needed.

Partial render is supported only by those cells whose cell renderer supports it by returning before rendering (based on config.snapshot).

On reset

Defers to paintCellsByColumnsAndRows, which clears the canvas, draws the grid, and draws the grid lines.

On the next call (after reset)

Each cell is drawn redrawn only when its appearance changes. This determination is made by the cell renderer by comparing with (and maintaining) config.snapshot. See SimpleCell for a sample implementation.

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.

On subsequent calls

Iterates through each cell, calling _paintCell with undefined prefill color. This signifies partial render to the SimpleCell cell renderer, which only renders the cell when it's text, font, or colors have changed.

Each cell to be rendered is described by a 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 reset on each.

See also the discussion of clipping in paintCellsByColumns.

This:
Parameters:
Name Type Description
gc CanvasRenderingContext2D

paintCellsByColumns(gc)

Render the grid with consolidated column rects.

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 columns with their own background color that differs from the grid background color, these are consolidated and the consolidated groups of column backgrounds are all drawn before iterating through 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 (grid.properties.columnClip = true but 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 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 reset on each.

Regading clipping. The reason for clipping is to prevent text from overflowing into the next column. However there is a serious performance cost.

For performance reasons _paintCell does not set up a clipping region for each cell. However, iff grid property columnClip is truthy, this grid renderer will set up a clipping region to prevent text overflow to right. If columnClip is null, a clipping region will only be set up on the last column. Otherwise, there will be no clipping region.

The idea of clipping just the last column is because in addition to the optional graphics clipping, we also clip ("truncate") text. Text can be truncated conservatively so it will never overflow. The problem with this is that characters vanish as they hit the right cell boundary, which may or may be obvious depending on font size. Alternatively, text can be truncated so that the overflow will be a maximum of 1 character. This allows partial characters to be rendered. But this is where graphics clipping is required.

When renderering column by column as this particular renderer does, and when the background color of the next cell to the right is opaque (alpha = 1), clipping can be turned off because each column will overpaint any text that overflowed from the one before. However, any text that overflows the last column will paint into unused canvas region to the right of the grid. This is the raison d'ĂȘtre for "clip last column only" option mentioned above (when columnClip is set to null). To avoid even this performance cost (of clipping just the last column), column widths can be set to fill the available canvas.

Note that text never overflows to left because text starting point is never < 0. The reason we don't clip to the left is for cell renderers that need to re-render to the left to produce a merged cell effect, such as grouped column header.

This:
Parameters:
Name Type Description
gc CanvasRenderingContext2D

paintCellsByColumnsAndRows(gc)

Render the grid with consolidated row OR column rects.

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 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 reset on each.

See also the discussion of clipping in paintCellsByColumns.

This:
Parameters:
Name Type Description
gc CanvasRenderingContext2D

paintCellsByColumnsDiscrete(gc)

Render the grid with discrete column rects.

Paints all the cells of a grid, one column at a time.

In this grid renderer, a background rect is not drawn using the grid background color.

Rather, all columns paint their own background rects, with color defaulting to grid background color.

The idea of painting each column rect is to "clip" text that might have overflowed from the previous column by painting over it with the background from this column. Only the last column will show overflowing text, and only if the canvas width exceeds the grid width. If this is the case, you can turn on clipping for the last column only by setting columnClip to true for the last column.

NOTE: As a convenience feature, setting columnClip to null will clip only the last column, so simply setting it on the grid (rather than the last column) will have the same effect. This is much more convenient because you don't have to worry about the last column being redefined (moved, hidden, etc).

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 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 reset on each.

See also the discussion of clipping in paintCellsByColumnsDiscrete.

This:
Parameters:
Name Type Description
gc CanvasRenderingContext2D

paintCellsByRows(gc)

Render the grid.

NOTE: This grid renderer is not as performant as the others and it's use is not recommended if you care about performance. The reasons for the wanting performance are unclear, possibly having to do with the way Chrome optimizes access to the column objects?

Paints all the cells of a grid, one row 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.

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 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 reset on each.

See also the discussion of clipping in paintCellsByColumns.

This:
Parameters:
Name Type Description
gc CanvasRenderingContext2D

paintGridlines(gc)

We opted to not paint borders for each cell as that was extremely expensive. Instead we draw grid lines here.

Parameters:
Name Type Description
gc CanvasRenderingContext2D

renderGrid(gc)

This is the main forking of the renderering task.

dataModel.fetchData callback renders the grid. Note however that this is not critical when the clock is running as it will be rendered on the next tick. We let it call it anyway in case (1) fetch returns quickly enough to be rendered on this tick rather than next or (2) clock isn't running (for debugging purposes).

Parameters:
Name Type Description
gc CanvasRenderingContext2D

renderOverride(gc, override)

copy each overrides specified area to it's target and blank out the source area

Parameters:
Name Type Description
gc CanvasRenderingContext2D
override OverrideObject

an object with details contain an area and a target context

renderOverrides(gc)

iterate the renderering overrides and manifest each

Parameters:
Name Type Description
gc CanvasRenderingContext2D