export interface Cell { row: number col: number } export class CellRange { _start: Cell | null _end: Cell | null _oldStart: Cell | null _oldEnd: Cell | null constructor(start = null, end = null) { this._start = start this._end = end ?? this._start this._oldStart = start this._oldEnd = end ?? this._start } isEmpty() { return this._start == null || this._end == null } isSingleCell() { return !this.isEmpty() && this._start?.col === this._end?.col && this._start?.row === this._end?.row } isSingleRow() { return !this.isEmpty() && this._start?.row === this._end?.row } isCellInRange(cell: Cell) { return ( !this.isEmpty() && cell.row >= this.start.row && cell.row <= this.end.row && cell.col >= this.start.col && cell.col <= this.end.col ) } isRowInRange(row: number) { return !this.isEmpty() && row >= this.start.row && row <= this.end.row } isColInRange(col: number) { return !this.isEmpty() && col >= this.start.col && col <= this.end.col } isDifferentColSelection() { if (this.isEmpty() || this.isSingleCell()) return false return this.oldStart.col !== this.start.col || this.oldEnd.col !== this.end.col } get start(): Cell { return { row: Math.min(this._start?.row ?? NaN, this._end?.row ?? NaN), col: Math.min(this._start?.col ?? NaN, this._end?.col ?? NaN), } } get oldStart(): Cell { return { row: Math.min(this._oldStart?.row ?? NaN, this._oldEnd?.row ?? NaN), col: Math.min(this._oldStart?.col ?? NaN, this._oldEnd?.col ?? NaN), } } get end(): Cell { return { row: Math.max(this._start?.row ?? NaN, this._end?.row ?? NaN), col: Math.max(this._start?.col ?? NaN, this._end?.col ?? NaN), } } get oldEnd(): Cell { return { row: Math.max(this._oldStart?.row ?? NaN, this._oldEnd?.row ?? NaN), col: Math.max(this._oldStart?.col ?? NaN, this._oldEnd?.col ?? NaN), } } get cellCount(): number { if (this.isEmpty()) return 0 const rows = this.end.row - this.start.row + 1 const cols = this.end.col - this.start.col + 1 return rows * cols } startRange(value: Cell) { this._start = value this._end = value this._oldStart = value this._oldEnd = value } endRange(value: Cell) { this._oldEnd = this._end this._end = value } clear() { this._oldStart = this._start this._oldEnd = this._end this._start = null this._end = null } }