UNPKG

tui-grid

Version:

TOAST UI Grid : Powerful data grid control supported by TOAST UI

158 lines (132 loc) 5.18 kB
/** * @fileoverview Render model to be used for smart-rendering * @author NHN. FE Development Lab <dl_javascript@nhn.com> */ 'use strict'; var _ = require('underscore'); var Renderer = require('./renderer'); var dimensionConst = require('../common/constMap').dimension; var CELL_BORDER_WIDTH = dimensionConst.CELL_BORDER_WIDTH; // The ratio of buffer size to bodyHeight var BUFFER_RATIO = 0.3; // The ratio of the size bodyHeight which can cause to refresh the rendering range var BUFFER_HIT_RATIO = 0.1; /** * Render model to be used for smart-rendering * @module model/renderer-smart * @extends module:model/renderer * @ignore */ var SmartRenderer = Renderer.extend(/** @lends module:model/renderer-smart.prototype */{ initialize: function() { Renderer.prototype.initialize.apply(this, arguments); this.on('change:scrollTop', this._onChangeScrollTop, this); this.listenTo(this.dimensionModel, 'change:bodyHeight', this._onChangeBodyHeight); }, /** * Event handler for change:scrollTop event * @private */ _onChangeScrollTop: function() { if (this._shouldRefresh(this.get('scrollTop'))) { this._setRenderingRange(); } }, /** * Event handler for change:bodyHeight event on model/dimension * @private */ _onChangeBodyHeight: function() { this._setRenderingRange(); }, /** * Calculate the range to render and set the attributes. * @param {boolean} silent - whether set attributes silently * @private */ _setRenderingRange: function(silent) { var scrollTop = this.get('scrollTop'); var dimensionModel = this.dimensionModel; var dataModel = this.dataModel; var coordRowModel = this.coordRowModel; var bodyHeight = dimensionModel.get('bodyHeight'); var bufferSize = parseInt(bodyHeight * BUFFER_RATIO, 10); var startIndex = Math.max(coordRowModel.indexOf(scrollTop - bufferSize), 0); var endIndex = Math.min(coordRowModel.indexOf(scrollTop + bodyHeight + bufferSize), dataModel.length - 1); var top, bottom; if (dataModel.isRowSpanEnable()) { startIndex += this._getStartRowSpanMinCount(startIndex); endIndex += this._getEndRowSpanMaxCount(endIndex); } top = coordRowModel.getOffsetAt(startIndex); bottom = coordRowModel.getOffsetAt(endIndex) + coordRowModel.getHeightAt(endIndex) + CELL_BORDER_WIDTH; this.set({ top: top, bottom: bottom, startIndex: startIndex, endIndex: endIndex }, { silent: silent }); }, /** * 렌더링을 시작하는 행에 rowSpan 정보가 있으면, count 값이 가장 작은 행의 값을 반환한다. * @param {number} startIndex 시작하는 행의 Index * @returns {number} rowSpan의 count 값 (0 이하) * @private */ _getStartRowSpanMinCount: function(startIndex) { var firstRow = this.dataModel.at(startIndex); var result = 0; var counts; if (firstRow) { counts = _.pluck(firstRow.getRowSpanData(), 'count'); counts.push(0); // count가 음수인 경우(mainRow가 아닌 경우)에만 최소값을 구함. 없으면 0 result = _.min(counts); } return result; }, /** * 렌더링할 마지막 행에 rowSpan 정보가 있으면, count 값이 가장 큰 행의 값을 반환한다. * @param {number} endIndex 마지막 행의 Index * @returns {number} rowSpan의 count 값 (0 이상) * @private */ _getEndRowSpanMaxCount: function(endIndex) { var lastRow = this.dataModel.at(endIndex); var result = 0; var counts; if (lastRow) { counts = _.pluck(lastRow.getRowSpanData(), 'count'); counts.push(0); // count가 양수인 경우(mainRow인 경우)에만 최대값을 구함. 없으면 0 result = _.max(counts); } // subtract 1, as the count includes main-cell itself if (result > 0) { result -= 1; } return result; }, /** * Returns whether the scroll potision hits the buffer limit or not. * @param {number} scrollTop - scroll top * @returns {boolean} * @private */ _shouldRefresh: function(scrollTop) { var bodyHeight = this.dimensionModel.get('bodyHeight'); var scrollBottom = scrollTop + bodyHeight; var totalRowHeight = this.dimensionModel.get('totalRowHeight'); var top = this.get('top'); var bottom = this.get('bottom'); var bufferHitSize = parseInt(bodyHeight * BUFFER_HIT_RATIO, 10); var hitTopBuffer = (scrollTop - top) < bufferHitSize; var hitBottomBuffer = (bottom - scrollBottom) < bufferHitSize; return (hitTopBuffer && top > 0) || (hitBottomBuffer && bottom < totalRowHeight); } }); // exports consts for external use SmartRenderer.BUFFER_RATIO = BUFFER_RATIO; SmartRenderer.BUFFER_HIT_RATIO = BUFFER_HIT_RATIO; module.exports = SmartRenderer;