UNPKG

tui-grid

Version:

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

259 lines (221 loc) 9.11 kB
/** * @fileoverview Converts coordinates to index of rows and columns * @author NHN. FE Development Lab <dl_javascript@nhn.com> */ 'use strict'; var snippet = require('tui-code-snippet'); var Model = require('../base/model'); var dimensionConstMap = require('../common/constMap').dimension; var TABLE_BORDER_WIDTH = dimensionConstMap.TABLE_BORDER_WIDTH; var CELL_BORDER_WIDTH = dimensionConstMap.CELL_BORDER_WIDTH; /** * @module model/coordConverter * @param {Object} attrs - Attributes * @param {Object} options - Options * @extends module:base/model * @ignore */ var CoordConverter = Model.extend(/** @lends module:model/coordConverter.prototype */{ initialize: function(attrs, options) { this.dataModel = options.dataModel; this.columnModel = options.columnModel; this.focusModel = options.focusModel; this.dimensionModel = options.dimensionModel; this.renderModel = options.renderModel; this.coordRowModel = options.coordRowModel; this.coordColumnModel = options.coordColumnModel; this.listenTo(this.focusModel, 'focus', this._onFocus); }, /** * Get cell index from mouse position * @param {Number} pageX - Mouse X-position based on page * @param {Number} pageY - Mouse Y-position based on page * @param {boolean} [withMeta] - Whether the meta columns go with this calculation * @returns {{row: number, column: number}} Cell index */ getIndexFromMousePosition: function(pageX, pageY, withMeta) { var position = this.dimensionModel.getPositionFromBodyArea(pageX, pageY); var posWithScroll = this._getScrolledPosition(position); return { row: this.coordRowModel.indexOf(posWithScroll.y), column: this.coordColumnModel.indexOf(posWithScroll.x, withMeta) }; }, /** * Returns the scrolled position in addition to given position * @param {{x: number, y: number}} position - position * @returns {{x: number, y: number}} * @private */ _getScrolledPosition: function(position) { var renderModel = this.renderModel; var isRside = position.x > this.dimensionModel.get('lsideWidth'); var scrollLeft = isRside ? renderModel.get('scrollLeft') : 0; var scrollTop = renderModel.get('scrollTop'); return { x: position.x + scrollLeft, y: position.y + scrollTop }; }, /** * Returns the count of rowspan of given cell * @param {Number} rowKey - row key * @param {String} columnName - column name * @returns {Number} * @private */ _getRowSpanCount: function(rowKey, columnName) { var rowSpanData = this.dataModel.get(rowKey).getRowSpanData(columnName); if (!rowSpanData.isMainRow) { rowKey = rowSpanData.mainRowKey; rowSpanData = this.dataModel.get(rowKey).getRowSpanData(columnName); } return rowSpanData.count || 1; }, /** * Returns the vertical position of the given row * @param {Number} rowKey - row key * @param {Number} rowSpanCount - the count of rowspan * @returns {{top: Number, bottom: Number}} * @private */ _getCellVerticalPosition: function(rowKey, rowSpanCount) { var firstIdx, lastIdx, top, bottom; var coordRowModel = this.coordRowModel; firstIdx = this.dataModel.indexOfRowKey(rowKey); lastIdx = firstIdx + rowSpanCount - 1; top = coordRowModel.getOffsetAt(firstIdx); bottom = coordRowModel.getOffsetAt(lastIdx) + coordRowModel.getHeightAt(lastIdx) + CELL_BORDER_WIDTH; return { top: top, bottom: bottom }; }, /** * Returns the horizontal position of the given column * @param {String} columnName - column name * @returns {{left: Number, right: Number}} * @private */ _getCellHorizontalPosition: function(columnName) { var columnModel = this.columnModel; var metaColumnCount = columnModel.getVisibleMetaColumnCount(); var widths = this.coordColumnModel.get('widths'); var leftColumnCount = columnModel.getVisibleFrozenCount() + metaColumnCount; var targetIdx = columnModel.indexOfColumnName(columnName, true) + metaColumnCount; var idx = leftColumnCount > targetIdx ? 0 : leftColumnCount; var left = 0; for (; idx < targetIdx; idx += 1) { left += widths[idx] + CELL_BORDER_WIDTH; } return { left: left, right: left + widths[targetIdx] + CELL_BORDER_WIDTH }; }, /** * Returns the bounds of the cell identified by given address * @param {Number|String} rowKey - row key * @param {String} columnName - column name * @returns {{top: number, left: number, right: number, bottom: number}} * @todo TC */ getCellPosition: function(rowKey, columnName) { var rowSpanCount, vPos, hPos; rowKey = this.dataModel.getMainRowKey(rowKey, columnName); if (!this.dataModel.get(rowKey)) { return {}; } rowSpanCount = this._getRowSpanCount(rowKey, columnName); vPos = this._getCellVerticalPosition(rowKey, rowSpanCount); hPos = this._getCellHorizontalPosition(columnName); return { top: vPos.top, bottom: vPos.bottom, left: hPos.left, right: hPos.right }; }, /** * Judge scroll direction. * @param {{top: number, bottom: number, left: number, right: number}} targetPosition - Position of target element * @param {boolean} isRsideColumn - Whether the target cell is in rside * @param {{height: number, rsideWidth: number}} bodySize - Using cached bodySize * @returns {{isUp: boolean, isDown: boolean, isLeft: boolean, isRight: boolean}} Direction * @private */ _judgeScrollDirection: function(targetPosition, isRsideColumn, bodySize) { var renderModel = this.renderModel; var currentTop = renderModel.get('scrollTop'); var currentLeft = renderModel.get('scrollLeft'); var isUp, isDown, isLeft, isRight; isUp = targetPosition.top < currentTop; isDown = !isUp && (targetPosition.bottom > (currentTop + bodySize.height)); if (isRsideColumn) { isLeft = targetPosition.left < currentLeft; isRight = !isLeft && (targetPosition.right > (currentLeft + bodySize.rsideWidth - 1)); } else { isLeft = isRight = false; } return { isUp: isUp, isDown: isDown, isLeft: isLeft, isRight: isRight }; }, /** * Scroll to focus * @param {number} rowKey - row key * @param {string} columnName - column name * @param {boolean} shouldScroll - whether scroll to the target cell * @private */ _onFocus: function(rowKey, columnName, shouldScroll) { var scrollPosition; if (!shouldScroll) { return; } scrollPosition = this.getScrollPosition(rowKey, columnName); if (!snippet.isEmpty(scrollPosition)) { this.renderModel.set(scrollPosition); } }, /** * Make scroll position * @param {{isUp: boolean, isDown: boolean, isLeft: boolean, isRight: boolean}} scrollDirection - Direction * @param {{top: number, bottom: number, left: number, right: number}} targetPosition - Position of target element * @param {{height: number, rsideWidth: number}} bodySize - Using cached bodySize * @returns {{scrollLeft: ?Number, scrollTop: ?Number}} Position to scroll * @private */ _makeScrollPosition: function(scrollDirection, targetPosition, bodySize) { var pos = {}; if (scrollDirection.isUp) { pos.scrollTop = targetPosition.top; } else if (scrollDirection.isDown) { pos.scrollTop = targetPosition.bottom - bodySize.height; } if (scrollDirection.isLeft) { pos.scrollLeft = targetPosition.left; } else if (scrollDirection.isRight) { pos.scrollLeft = targetPosition.right - bodySize.rsideWidth + TABLE_BORDER_WIDTH; } return pos; }, /** * Return scroll position from the received index * @param {Number|String} rowKey - Row-key of target cell * @param {String} columnName - Column name of target cell * @returns {{scrollLeft: ?Number, scrollTop: ?Number}} Position to scroll */ getScrollPosition: function(rowKey, columnName) { var isRsideColumn = !this.columnModel.isLside(columnName); var targetPosition = this.getCellPosition(rowKey, columnName); var bodySize = this.dimensionModel.getBodySize(); var scrollDirection = this._judgeScrollDirection(targetPosition, isRsideColumn, bodySize); return this._makeScrollPosition(scrollDirection, targetPosition, bodySize); } }); module.exports = CoordConverter;