import { CellRef } from "../../types"; import excursion from "./excursion"; import { getRenderedCell, RenderedCell, RenderedGrid } from "./renderGrid"; import { GridSelection } from "./selection"; export interface SelectionStyles { activeCellStroke: string; selectionRangeFill: string; selectionRangeStroke: string; } function strokeActiveCell( ctx: CanvasRenderingContext2D, styles: SelectionStyles, grid: RenderedGrid, cell: RenderedCell, ) { excursion(ctx, () => { const isLastCell = cell.rect.bottomRight.x === grid.rect.bottomRight.x; const isLastRow = cell.rect.bottomRight.y === grid.rect.bottomRight.y; ctx.strokeStyle = styles.activeCellStroke; ctx.lineWidth = 2; ctx.strokeRect( cell.rect.topLeft.x + 1, cell.rect.topLeft.y + 1, isLastCell ? cell.rect.width - 2 : cell.rect.width - 1, isLastRow ? cell.rect.height - 2 : cell.rect.height - 1, ); }); } function drawCellRange( ctx: CanvasRenderingContext2D, styles: SelectionStyles, grid: RenderedGrid, start: CellRef, end: CellRef, { stroke }: { stroke: boolean }, ) { excursion(ctx, () => { const startCell = getRenderedCell(grid, start); const endCell = getRenderedCell(grid, end); if (!startCell || !endCell) return; const rect = startCell.rect.extend(endCell.rect); const isRightEdge = rect.bottomRight.x === grid.rect.bottomRight.x; const isBottomEdge = rect.bottomRight.y === grid.rect.bottomRight.y; ctx.fillStyle = styles.selectionRangeFill; ctx.fillRect( rect.topLeft.x + 1, rect.topLeft.y + 1, isRightEdge ? rect.width - 2 : rect.width - 1, isBottomEdge ? rect.height - 2 : rect.height - 1, ); if (!stroke) return; ctx.strokeStyle = styles.selectionRangeStroke; ctx.strokeRect( rect.topLeft.x + 0.5, rect.topLeft.y + 0.5, isRightEdge ? rect.width - 1 : rect.width, isBottomEdge ? rect.height - 1 : rect.height, ); }); } export default function drawSelection( ctx: CanvasRenderingContext2D, styles: SelectionStyles, grid: RenderedGrid, selection: GridSelection | undefined, { pending }: { pending: boolean }, ) { ctx.clearRect(0, 0, grid.rect.width, grid.rect.height); if (!selection) return; const activeCell = getRenderedCell(grid, selection.activeCellRef); if (!activeCell) return; if (selection.range) { drawCellRange(ctx, styles, grid, selection.range[0], selection.range[1], { stroke: !pending, }); } strokeActiveCell(ctx, styles, grid, activeCell); }