From b4aa4a4b67bfb220b92be75796e7976af0d6bdc1 Mon Sep 17 00:00:00 2001 From: Eugene Date: Fri, 21 Jul 2023 11:07:03 +0300 Subject: [PATCH] Added selection calculating Todo: Move listeners from scroller (handlers) --- src/components/scroller.ts | 45 ++++++++++++++++++++++++++++++++------ src/components/sheet.ts | 20 +++++++++++++++++ src/main.ts | 7 ++++++ src/modules/cell.ts | 7 +++--- src/modules/renderBox.ts | 5 +++-- src/scss/_spreadsheet.scss | 4 ++++ 6 files changed, 76 insertions(+), 12 deletions(-) diff --git a/src/components/scroller.ts b/src/components/scroller.ts index 6d5d7ce..5bf6ceb 100644 --- a/src/components/scroller.ts +++ b/src/components/scroller.ts @@ -12,6 +12,8 @@ export class Scroller { private verticalScroller: HTMLDivElement private horizontalScroller: HTMLDivElement private root: Spreadsheet + + private isSelecting = false constructor(root: Spreadsheet) { this.root = root @@ -26,16 +28,45 @@ export class Scroller { this.updateScrollerSize() //* Init size set this.element.addEventListener('scroll', this.handleScroll) + + this.element.addEventListener('mousedown', this.handleClick) + this.element.addEventListener('mousemove', event => { + if(!this.isSelecting) return; + const {offsetX, offsetY} = event + const lastSelectedCell = this.root.getCellByCoords(offsetX, offsetY) + if(this.root.selection.selectedRange) { + this.root.selection.selectedRange.to = lastSelectedCell + } + }) + this.element.addEventListener('mouseup', () => { + this.isSelecting = false + + console.log(this.root.selection) + }) + } - handleScroll = () => { + private handleClick = (event: MouseEvent) => { + const {offsetX, offsetY} = event + const clickedCell = this.root.getCellByCoords(offsetX, offsetY) + this.isSelecting = true + this.root.selection.selectedRange = { + from: clickedCell, + to: clickedCell + } + this.root.selection.selectedCell = clickedCell + + this.root.renderSheet() + } + + private handleScroll = () => { const rect = this.getViewportBoundlingRect() this.root.viewport.updateValues(rect) this.root.renderSheet() } - getViewportBoundlingRect(): ViewportRect { + public getViewportBoundlingRect(): ViewportRect { const { scrollTop, scrollLeft } = this.element const { height, width } = this.element.getBoundingClientRect() const bottom = scrollTop + height @@ -49,7 +80,7 @@ export class Scroller { } } - buildComponent() { + private buildComponent() { const scroller = document.createElement('div') const verticalScroller = document.createElement('div') const horizontalScroller = document.createElement('div') @@ -74,14 +105,14 @@ export class Scroller { return { scroller, verticalScroller, horizontalScroller } } - getActualHeight() { + private getActualHeight() { return this.root.config.rows.reduce((acc, curr) => { acc += curr.height return acc }, 0) } - getActualWidth() { + private getActualWidth() { return this.root.config.columns.reduce((acc, curr) => { acc += curr.width return acc @@ -96,11 +127,11 @@ export class Scroller { this.setScrollerWidth(totalWidth) } - setScrollerHeight(height: number) { + private setScrollerHeight(height: number) { this.verticalScroller.style.height = height + 'px' } - setScrollerWidth(width: number) { + private setScrollerWidth(width: number) { this.horizontalScroller.style.width = width + 'px' } } \ No newline at end of file diff --git a/src/components/sheet.ts b/src/components/sheet.ts index f8f8c3f..1a6ee2f 100644 --- a/src/components/sheet.ts +++ b/src/components/sheet.ts @@ -27,6 +27,26 @@ export class Sheet { } + getCellByCoords(x: number, y: number): Position { + let row = 0; + let height = 0 + while(height <= y) { + height += this.root.config.rows[row].height + if(height >= y) break; + row++; + } + + let col = 0; + let width = 0; + while(width <= x) { + width += this.root.config.columns[col].width + if(width >= x) break; + col++; + } + + return new Position(row, col) + } + renderCell(position: Position) { const {column, row} = position this.root.data[row][column].render(this.root) diff --git a/src/main.ts b/src/main.ts index 0d7c5da..c5ecfdf 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,6 +6,7 @@ import { Table } from "./components/table"; import { Toolbar } from "./components/toolbar"; import { Cell } from "./modules/cell"; import { Config, ViewProperties } from "./modules/config"; +import { Selection } from "./modules/selection"; import { Styles } from "./modules/styles"; import { Viewport } from "./modules/viewport"; import './scss/main.scss' @@ -39,6 +40,7 @@ export class Spreadsheet { public config: Config public data: Cell[][] public viewport: Viewport + public selection: Selection constructor(target: string | HTMLElement, props?: SpreadsheetConstructorProperties) { const config = createSampleConfig(750, 750) @@ -55,6 +57,7 @@ export class Spreadsheet { this.header = new Header(this) this.editor = new Editor(this) this.viewport = new Viewport(this, this.scroller.getViewportBoundlingRect()) + this.selection = new Selection() this.data = data @@ -94,6 +97,10 @@ export class Spreadsheet { return this.config.view } + getCellByCoords(x: number, y: number) { + return this.sheet.getCellByCoords(x, y) + } + renderSheet() { this.sheet.renderSheet() } diff --git a/src/modules/cell.ts b/src/modules/cell.ts index 5ee3e56..e555314 100644 --- a/src/modules/cell.ts +++ b/src/modules/cell.ts @@ -34,18 +34,19 @@ export class Cell { let {height, width, x, y} = new RenderBox(root.config, this.position) const { ctx } = root + const isCellSelected = (root.selection.selectedCell?.row === this.position.row && root.selection.selectedCell.column === this.position.column) y -= root.viewport.top x -= root.viewport.left ctx.clearRect(x, y, width, height) - ctx.fillStyle = 'white' + ctx.fillStyle = isCellSelected ? 'red' : 'white' ctx.strokeStyle = 'black' - ctx.fillRect(x + 1, y + 1, width - 1, height - 1) + ctx.fillRect(x, y, width - 1, height - 1) ctx.strokeRect(x, y, width, height) ctx.fillStyle = 'black' ctx.textAlign = 'left' - ctx.font = '16px Arial' + ctx.font = `16px Arial` ctx.textBaseline = 'middle' ctx.fillText(this.displayValue, x + 2, y + height / 2, width) } diff --git a/src/modules/renderBox.ts b/src/modules/renderBox.ts index a9d70cc..489873d 100644 --- a/src/modules/renderBox.ts +++ b/src/modules/renderBox.ts @@ -7,6 +7,7 @@ export class RenderBox { width: number height: number constructor(config: Config, cellPosition: Position) { + this.x = this.getXCoord(cellPosition.column, config) this.y = this.getYCoord(cellPosition.row, config) this.width = config.columns[cellPosition.column].width @@ -16,7 +17,7 @@ export class RenderBox { private getXCoord(column: number, config: Config): number { let x = 0; - for(let i = 0; i < column; i++) { + for (let i = 0; i < column; i++) { x += config.columns[i].width } @@ -25,7 +26,7 @@ export class RenderBox { private getYCoord(row: number, config: Config): number { let y = 0 - for(let i = 0; i < row; i++) { + for (let i = 0; i < row; i++) { y += config.rows[i].height } return y diff --git a/src/scss/_spreadsheet.scss b/src/scss/_spreadsheet.scss index 82563aa..da2b915 100644 --- a/src/scss/_spreadsheet.scss +++ b/src/scss/_spreadsheet.scss @@ -1,3 +1,5 @@ + + .content { position: absolute; top: 0; @@ -5,7 +7,9 @@ } .spreadsheet_container { + position: relative; isolation: isolate; + border: 2px solid black; } .sheet{