import { type Item, type Rectangle } from "../data-grid-types.js"; import { type MappedGridColumn, isGroupEqual } from "./data-grid-lib.js"; export function getSkipPoint(drawRegions: readonly Rectangle[]): number | undefined { if (drawRegions.length === 0) return undefined; let drawRegionsLowestY: number | undefined; for (const dr of drawRegions) { drawRegionsLowestY = Math.min(drawRegionsLowestY ?? dr.y, dr.y); } } export type WalkRowsCallback = ( drawY: number, row: number, rowHeight: number, isSticky: boolean, isTrailingRow: boolean ) => boolean | void; export function walkRowsInCol( startRow: number, drawY: number, height: number, rows: number, getRowHeight: (row: number) => number, freezeTrailingRows: number, hasAppendRow: boolean, skipToY: number | undefined, cb: WalkRowsCallback ): void { skipToY = skipToY ?? drawY; let y = drawY; let row = startRow; const rowEnd = rows - freezeTrailingRows; let didBreak = false; while (y < height && row < rowEnd) { const rh = getRowHeight(row); if (y + rh > skipToY && cb(y, row, rh, false, hasAppendRow && row === rows - 1) === true) { didBreak = true; break; } y += rh; row++; } if (didBreak) return; y = height; for (let fr = 0; fr < freezeTrailingRows; fr++) { row = rows - 1 - fr; const rh = getRowHeight(row); y -= rh; cb(y, row, rh, true, hasAppendRow && row === rows - 1); } } export type WalkColsCallback = ( col: MappedGridColumn, drawX: number, drawY: number, clipX: number, startRow: number ) => boolean | void; export function walkColumns( effectiveCols: readonly MappedGridColumn[], cellYOffset: number, translateX: number, translateY: number, totalHeaderHeight: number, cb: WalkColsCallback ): void { let x = 0; let clipX = 0; // this tracks the total width of sticky cols const drawY = totalHeaderHeight + translateY; for (const c of effectiveCols) { const drawX = c.sticky ? clipX : x + translateX; if (cb(c, drawX, drawY, c.sticky ? 0 : clipX, cellYOffset) === true) { break; } x += c.width; clipX += c.sticky ? c.width : 0; } } // this should not be item, it is [startInclusive, endInclusive] export type WalkGroupsCallback = ( colSpan: Item, group: string, x: number, y: number, width: number, height: number ) => void; export function walkGroups( effectiveCols: readonly MappedGridColumn[], width: number, translateX: number, groupHeaderHeight: number, cb: WalkGroupsCallback ): void { let x = 0; let clipX = 0; for (let index = 0; index < effectiveCols.length; index++) { const startCol = effectiveCols[index]; let end = index + 1; let boxWidth = startCol.width; if (startCol.sticky) { clipX += boxWidth; } while ( end < effectiveCols.length && isGroupEqual(effectiveCols[end].group, startCol.group) && effectiveCols[end].sticky === effectiveCols[index].sticky ) { const endCol = effectiveCols[end]; boxWidth += endCol.width; end++; index++; if (endCol.sticky) { clipX += endCol.width; } } const t = startCol.sticky ? 0 : translateX; const localX = x + t; const delta = startCol.sticky ? 0 : Math.max(0, clipX - localX); const w = Math.min(boxWidth - delta, width - (localX + delta)); cb( [startCol.sourceIndex, effectiveCols[end - 1].sourceIndex], startCol.group ?? "", localX + delta, 0, w, groupHeaderHeight ); x += boxWidth; } } export function getSpanBounds( span: Item, cellX: number, cellY: number, cellW: number, cellH: number, column: MappedGridColumn, allColumns: readonly MappedGridColumn[] ): [Rectangle | undefined, Rectangle | undefined] { const [startCol, endCol] = span; let frozenRect: Rectangle | undefined; let contentRect: Rectangle | undefined; const firstNonSticky = allColumns.find(x => !x.sticky)?.sourceIndex ?? 0; if (endCol > firstNonSticky) { const renderFromCol = Math.max(startCol, firstNonSticky); let tempX = cellX; let tempW = cellW; for (let x = column.sourceIndex - 1; x >= renderFromCol; x--) { tempX -= allColumns[x].width; tempW += allColumns[x].width; } for (let x = column.sourceIndex + 1; x <= endCol; x++) { tempW += allColumns[x].width; } contentRect = { x: tempX, y: cellY, width: tempW, height: cellH, }; } if (firstNonSticky > startCol) { const renderToCol = Math.min(endCol, firstNonSticky - 1); let tempX = cellX; let tempW = cellW; for (let x = column.sourceIndex - 1; x >= startCol; x--) { tempX -= allColumns[x].width; tempW += allColumns[x].width; } for (let x = column.sourceIndex + 1; x <= renderToCol; x++) { tempW += allColumns[x].width; } frozenRect = { x: tempX, y: cellY, width: tempW, height: cellH, }; } return [frozenRect, contentRect]; }