UNPKG

@1771technologies/lytenyte-pro

Version:

Blazingly fast headless React data grid with 100s of features.

89 lines (88 loc) 4.09 kB
/** * Splits a cell selection rectangle into multiple rectangles when it crosses specified boundary regions. * This is useful for handling selections that span across different grid sections (e.g., fixed columns/rows, * scrollable areas). * * The splitting process happens in two phases: * 1. Column-wise splitting: Splits rectangles that cross column section boundaries * 2. Row-wise splitting: Further splits the resulting rectangles if they cross row section boundaries * * Splitting does not support full width rows. It is assumed that if full width rows are present then * the cell selection will just be drawn over them * * @example * // For a grid with 2 fixed start columns and 1 fixed top row: * const splits = splitCellSelectionRect({ * rect: { columnStart: 0, columnEnd: 3, rowStart: 0, rowEnd: 2 }, * colStartCount: 2, // Number of fixed start columns * colCenterCount: 10, // Number of scrollable columns * rowTopCount: 1, // Number of fixed top rows * rowCenterCount: 50 // Number of scrollable rows * }); * * @param rect - The original cell selection rectangle to split * @param colStartCount - Number of columns in the start (usually fixed) section * @param colCenterCount - Number of columns in the center (usually scrollable) section * @param rowTopCount - Number of rows in the top (usually fixed) section * @param rowCenterCount - Number of rows in the center (usually scrollable) section * @returns An array of split rectangles. If no splits were necessary, returns an array with just the original rectangle */ export function splitCellSelectionRect({ rect, colStartCount, colCenterCount, rowTopCount, rowCenterCount, }) { // Calculate the boundary positions for columns const colStartBound = colStartCount; const colEndBound = colStartCount + colCenterCount; const isUnit = rect.rowEnd - rect.rowStart === 1 && rect.columnEnd - rect.columnStart === 1; const colSplits = []; // Handle column splits first // Case 1: Selection starts before the fixed columns and extends into the scrollable area if (rect.columnStart < colStartBound && rect.columnEnd > colStartBound) { const startSplit = { ...rect, columnEnd: colStartBound, isUnit, }; colSplits.push(startSplit); rect = { ...rect, columnStart: colStartBound }; } // Case 2: Selection starts in the scrollable area and extends into the end section if (rect.columnStart < colEndBound && rect.columnEnd > colEndBound) { const endSplit = { ...rect, columnStart: colEndBound, isUnit, }; rect = { ...rect, columnEnd: colEndBound }; colSplits.push(endSplit); } // Add the remaining rectangle after column splits colSplits.push({ ...rect, isUnit }); // Calculate the boundary positions for rows const topBound = rowTopCount; const bottomBound = rowTopCount + rowCenterCount; // Process row splits for each column-split rectangle const rowSplits = []; for (let split of colSplits) { // Case 1: Selection spans from top section into center section if (split.rowStart < topBound && split.rowEnd > topBound) { const topSplit = { ...split, rowEnd: topBound, isUnit }; split = { ...split, rowStart: topBound }; rowSplits.push(topSplit); } // Case 2: Selection spans from center section into bottom section if (split.rowStart < bottomBound && split.rowEnd > bottomBound) { const bottomSplit = { ...split, rowStart: bottomBound, isUnit, }; split = { ...split, rowEnd: bottomBound }; rowSplits.push(bottomSplit); } rowSplits.push(split); } return rowSplits .map((c) => ({ ...c, borderTop: true, borderBottom: true, borderEnd: true, borderStart: true })) .sort((l, r) => { return l.rowStart - r.rowStart || l.columnStart - r.columnStart; }); }