UNPKG

@antv/s2

Version:

effective spreadsheet render core lib

261 lines 9.88 kB
import { findIndex, isEmpty, isNil } from 'lodash'; import { FrozenGroupType } from '../common/constant/frozen'; import { DEFAULT_PAGE_INDEX } from '../common/constant/pagination'; export const isFrozenCol = (colIndex, frozenCount) => frozenCount > 0 && colIndex < frozenCount; export const isFrozenTrailingCol = (colIndex, frozenCount, colLength) => frozenCount > 0 && colIndex >= colLength - frozenCount; export const isFrozenRow = (rowIndex, minRowIndex, frozenCount) => frozenCount > 0 && rowIndex < minRowIndex + frozenCount; export const isFrozenTrailingRow = (rowIndex, maxRowIndex, frozenCount) => frozenCount > 0 && rowIndex >= maxRowIndex + 1 - frozenCount; /** * 计算偏移 scrollX、scrollY 的时候,在视窗中的节点索引 */ export const calculateInViewIndexes = (options) => { const { scrollX, scrollY, widths, heights, viewport, rowRemainWidth } = options; // 1. 计算 x min、max let xMin = findIndex(widths, (width, idx) => { const x = scrollX - (isNil(rowRemainWidth) ? 0 : rowRemainWidth) + viewport.x; return x >= width && x < widths[idx + 1]; }, 0); xMin = Math.max(xMin, 0); let xMax = findIndex(widths, (width, idx) => { const x = viewport.width + scrollX + viewport.x; return x >= width && x < widths[idx + 1]; }, xMin); xMax = Math.min(xMax === -1 ? Infinity : xMax, widths.length - 2); const { start: yMin, end: yMax } = heights.getIndexRange(scrollY + viewport.y, viewport.height + scrollY + viewport.y); return [xMin, xMax, yMin, yMax]; }; /** * 优化滚动方向,对于小角度的滚动,固定为一个方向 * @param x * @param y * @param ratio */ export const optimizeScrollXY = (x, y, ratio) => { // 调参工程师 const ANGLE = 2; const angle = Math.abs(x / y); // 经过滚动优化之后的 x, y const deltaX = angle <= 1 / ANGLE ? 0 : x; const deltaY = angle > ANGLE ? 0 : y; return [deltaX * ratio.horizontal, deltaY * ratio.vertical]; }; export const translateGroup = (group, scrollX, scrollY) => { if (group) { const [preX, preY] = group.getPosition(); group.translate(scrollX - preX, scrollY - preY); } }; export const translateGroupX = (group, scrollX) => { if (group) { const [preX] = group.getPosition(); group.translate(scrollX - preX, 0); } }; export const translateGroupY = (group, scrollY) => { if (group) { const [, preY] = group.getPosition(); group === null || group === void 0 ? void 0 : group.translate(0, scrollY - preY); } }; /** * frozen frozenTrailing * ColCount ColCount * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * | | frozenRow | | frozenRowCount * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * | fro | | fro | * | zen | panel | zen | * | col | scroll | trailing | * | | | col | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * | | frozenTrailingRow | | frozenTrailingRowCount * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @description returns which group data cell belongs in frozen mode */ export const getFrozenGroupTypeByCell = (meta, frozenOptions, colLength, cellRange) => { const { colCount = 0, rowCount = 0, trailingColCount = 0, trailingRowCount = 0, } = frozenOptions; const { colIndex, rowIndex } = meta; if (isFrozenRow(rowIndex, cellRange.start, rowCount)) { return FrozenGroupType.Row; } if (isFrozenTrailingRow(rowIndex, cellRange.end, trailingRowCount)) { return FrozenGroupType.TrailingRow; } if (isFrozenCol(colIndex, colCount)) { return FrozenGroupType.Col; } if (isFrozenTrailingCol(colIndex, trailingColCount, colLength)) { return FrozenGroupType.TrailingCol; } return FrozenGroupType.Scroll; }; /** * @description calculate all cells in frozen group's intersection region */ export const calculateFrozenCornerCells = (frozenOptions, colLength, cellRange) => { const { colCount: frozenColCount = 0, rowCount: frozenRowCount = 0, trailingColCount: frozenTrailingColCount = 0, trailingRowCount: frozenTrailingRowCount = 0, } = frozenOptions; const result = { [FrozenGroupType.TopLeft]: [], [FrozenGroupType.TopRight]: [], [FrozenGroupType.BottomLeft]: [], [FrozenGroupType.BottomRight]: [], }; // frozenColGroup with frozenRowGroup or frozenTrailingRowGroup. Top left and Bottom left corner. for (let i = 0; i < frozenColCount; i++) { for (let j = cellRange.start; j < cellRange.start + frozenRowCount; j++) { result[FrozenGroupType.TopLeft].push({ x: i, y: j, }); } if (frozenTrailingRowCount > 0) { for (let j = 0; j < frozenTrailingRowCount; j++) { const index = cellRange.end - j; result[FrozenGroupType.BottomLeft].push({ x: i, y: index, }); } } } // frozenTrailingColGroup with frozenRowGroup or frozenTrailingRowGroup. Top right and bottom right corner. for (let i = 0; i < frozenTrailingColCount; i++) { const colIndex = colLength - 1 - i; for (let j = cellRange.start; j < cellRange.start + frozenRowCount; j++) { result[FrozenGroupType.TopRight].push({ x: colIndex, y: j, }); } if (frozenTrailingRowCount > 0) { for (let j = 0; j < frozenTrailingRowCount; j++) { const index = cellRange.end - j; result[FrozenGroupType.BottomRight].push({ x: colIndex, y: index, }); } } } return result; }; /** * @description split all cells in current panel with five child group */ export const splitInViewIndexesWithFrozen = (indexes, frozenOptions, colLength, cellRange) => { const { colCount = 0, rowCount = 0, trailingColCount = 0, trailingRowCount = 0, } = frozenOptions; const centerIndexes = [...indexes]; // Cut off frozen cells from centerIndexes if (isFrozenCol(centerIndexes[0], colCount)) { centerIndexes[0] = colCount; } if (isFrozenTrailingCol(centerIndexes[1], trailingColCount, colLength)) { centerIndexes[1] = colLength - trailingColCount - 1; } if (isFrozenRow(centerIndexes[2], cellRange.start, rowCount)) { centerIndexes[2] = cellRange.start + rowCount; } if (isFrozenTrailingRow(centerIndexes[3], cellRange.end, trailingRowCount)) { centerIndexes[3] = cellRange.end - trailingRowCount; } // Calculate indexes for four frozen groups const frozenRowIndexes = [...centerIndexes]; frozenRowIndexes[2] = cellRange.start; frozenRowIndexes[3] = cellRange.start + rowCount - 1; const frozenColIndexes = [...centerIndexes]; frozenColIndexes[0] = 0; frozenColIndexes[1] = colCount - 1; const frozenTrailingRowIndexes = [...centerIndexes]; frozenTrailingRowIndexes[2] = cellRange.end + 1 - trailingRowCount; frozenTrailingRowIndexes[3] = cellRange.end; const frozenTrailingColIndexes = [...centerIndexes]; frozenTrailingColIndexes[0] = colLength - trailingColCount; frozenTrailingColIndexes[1] = colLength - 1; return { center: centerIndexes, frozenRow: frozenRowIndexes, frozenCol: frozenColIndexes, frozenTrailingCol: frozenTrailingColIndexes, frozenTrailingRow: frozenTrailingRowIndexes, }; }; export const getCellRange = (viewCellHeights, pagination) => { const heights = viewCellHeights; let start = 0; let end = heights.getTotalLength() - 1; if (pagination) { const { current = DEFAULT_PAGE_INDEX, pageSize } = pagination; start = Math.max((current - 1) * pageSize, 0); end = Math.min(current * pageSize - 1, heights.getTotalLength() - 1); } return { start, end, }; }; /** * 明细表多级表头根据一个 node 返回其所属顶层节点 * @param node * @returns {Node} */ export const getNodeRoot = (node) => { while (node.level !== 0) { node = node.parent; } return node; }; /** * 获取 columns 的所有叶子节点 * @param columns 列配置 * @returns {Array} 叶子节点列组成的数组 */ export const getLeafColumns = (columns) => { const leafs = []; const recursionFn = (list) => { list.forEach((column) => { if (typeof column === 'string' || !column.children) { leafs.push(column); } else { recursionFn(column.children); } }); }; recursionFn(columns); return leafs; }; /** * 获取 columns 的所有叶子节点的 key * @param columns 列配置 * @returns {Array<string>} 叶子节点列的key组成的数组 */ export const getLeafColumnsWithKey = (columns = []) => { const leafs = getLeafColumns(columns); return leafs.map((column) => { if (typeof column === 'string') { return column; } return column.field; }); }; /** * 获取一个 node 的最左叶子节点,找不到则返回自身 * @param node * @returns {Node} */ export const getLeftLeafNode = (node) => { const firstNode = node.children[0]; if (!firstNode) { return node; } return firstNode.isLeaf ? firstNode : getLeftLeafNode(firstNode); }; /** * fields 的 rows、columns、values 值都为空时,返回 true * @param {Fields} fields * @return {boolean} */ export const areAllFieldsEmpty = (fields) => { return (isEmpty(fields.rows) && isEmpty(fields.columns) && isEmpty(fields.values)); }; //# sourceMappingURL=utils.js.map