From 53e081435b9c1be8da504f474b8eaf3343ae88da Mon Sep 17 00:00:00 2001 From: Eugene Date: Tue, 25 Jul 2023 20:04:11 +0300 Subject: [PATCH] Added rows bar --- src/components/columnsBar.ts | 23 +++++++-- src/components/rowsBar.ts | 96 ++++++++++++++++++++++++++++++++++++ src/components/scroller.ts | 9 +++- src/components/table.ts | 2 +- src/components/toolbar.ts | 1 + src/main.ts | 36 ++++++++++++++ src/modules/renderBox.ts | 1 + 7 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 src/components/rowsBar.ts diff --git a/src/components/columnsBar.ts b/src/components/columnsBar.ts index 66fd8d2..1524107 100644 --- a/src/components/columnsBar.ts +++ b/src/components/columnsBar.ts @@ -5,7 +5,7 @@ export class ColumnsBar { private root: Spreadsheet public height: number = 32 public width: number - private resizerWidth = 2 + private resizerWidth = 1 ctx: CanvasRenderingContext2D constructor(root: Spreadsheet) { @@ -21,17 +21,21 @@ export class ColumnsBar { private createElement(): HTMLCanvasElement { const element = document.createElement('canvas') element.style.position = 'absolute' - element.style.top = '0' - element.style.left = '0' element.style.height = this.height + 'px' element.style.width = this.root.viewProps.width + 'px' element.style.display = 'block' + element.width = this.root.viewProps.width element.height = this.height return element } + public setElementPosition(top: number, left: number) { + this.element.style.top = top + 'px' + this.element.style.left = left + 'px' + } + private isColumnSelected(column: number): boolean { const { selectedCell, selectedRange } = this.root.selection if (selectedCell && selectedCell.column === column) return true @@ -45,6 +49,18 @@ export class ColumnsBar { return false } + private getYCoordWithOffset(renderBox: RenderBox): number { + const {y} = renderBox + + return y + this.root.toolbarHeight + } + + private getXCoordWithOffset(renderBox: RenderBox): number { + const {x} = renderBox + + return x + } + private renderText(column: number, renderBox: RenderBox) { const { width, x } = renderBox @@ -69,7 +85,6 @@ export class ColumnsBar { this.ctx.lineWidth = this.resizerWidth this.ctx.fillRect(x - this.root.viewport.left - 1, 1, width - 1, this.height - 1) this.ctx.strokeRect(x - this.root.viewport.left, 0, width, this.height) - } private renderSingleColumn(column: number) { diff --git a/src/components/rowsBar.ts b/src/components/rowsBar.ts new file mode 100644 index 0000000..11c5c46 --- /dev/null +++ b/src/components/rowsBar.ts @@ -0,0 +1,96 @@ +import Spreadsheet, { RenderBox } from "../main"; + +export class RowsBar { + element: HTMLCanvasElement + ctx: CanvasRenderingContext2D + root: Spreadsheet + width: number = 30 + height: number + resizerHeight = 1 + constructor(root: Spreadsheet) { + this.root = root + this.element = this.createElement() + const ctx = this.element.getContext('2d') + if (!ctx) throw new Error("Enable hardware acceleration"); + this.ctx = ctx + + this.height = this.root.viewProps.height + } + + private createElement() { + const element = document.createElement('canvas') + + element.style.position = 'absolute' + element.style.height = this.root.viewProps.height + 'px' + element.style.width = this.width + 'px' + element.style.display = 'block' + + + element.width = this.width + element.height = this.root.viewProps.height + return element + } + + public setElementPosition(top: number, left: number) { + this.element.style.top = top + 'px' + this.element.style.left = left + 'px' + } + + private isRowSelected(row: number): boolean { + const { selectedCell, selectedRange } = this.root.selection + if (selectedCell && selectedCell.row === row) return true + if (selectedRange) { + const inRange = + row >= Math.min(selectedRange.from.row, selectedRange.to.row) && + row <= Math.max(selectedRange.from.row, selectedRange.to.row) + + return inRange + } + return false + } + + + private renderText(row: number, renderBox: RenderBox) { + const { y, height } = renderBox + + this.ctx.fillStyle = 'black' + this.ctx.textAlign = 'left' + this.ctx.textBaseline = 'middle' + this.ctx.font = '16px Arial' + this.ctx.fillText(this.root.config.rows[row].title, 0 + 2, y - this.root.viewport.top + height / 2) + } + + private renderRect(column: number, renderBox: RenderBox) { + const { y, height } = renderBox + + + const isRowSeleted = this.isRowSelected(column) + + this.ctx.fillStyle = isRowSeleted ? this.root.styles.cells.selectedBackground : 'white' + this.ctx.strokeStyle = 'black' + this.ctx.lineWidth = this.resizerHeight + this.ctx.fillRect(0 + 1, y - this.root.viewport.top, this.width + 1, height) + this.ctx.strokeRect(0 + 1, y - this.root.viewport.top, this.width - 1, height) + } + + private renderSingleRow(row: number) { + const renderBox = new RenderBox(this.root.config, { + column: 0, + row: row + }) + + this.renderRect(row, renderBox) + this.renderText(row, renderBox) + } + + public renderBar() { + const lastRowIdx = this.root.viewport.lastRow + 3; + const firstRowIdx = this.root.viewport.firstRow; + + for (let col = firstRowIdx; col <= lastRowIdx; col++) { + this.renderSingleRow(col) + console.log(123) + } + } + +} \ No newline at end of file diff --git a/src/components/scroller.ts b/src/components/scroller.ts index c4891d8..fee6fda 100644 --- a/src/components/scroller.ts +++ b/src/components/scroller.ts @@ -26,6 +26,7 @@ export class Scroller { this.element.style.height = this.root.config.view.height + "px"; this.element.style.width = this.root.config.view.width + "px"; this.element.style.top = this.root.columnsBarHeight + 'px' + this.element.style.left = this.root.rowsBarWidth + 'px' this.element.tabIndex = -1; this.updateScrollerSize(); //* Init size set @@ -49,6 +50,7 @@ export class Scroller { } this.root.renderSheet(); this.root.renderColumnsBar(); + this.root.renderRowsBar(); }; private handleMouseUp = () => { @@ -67,6 +69,7 @@ export class Scroller { this.root.renderSheet(); this.root.renderColumnsBar(); + this.root.renderRowsBar(); }; private handleDoubleClick = (event: MouseEvent) => { @@ -166,7 +169,8 @@ export class Scroller { this.root.renderSheet(); this.root.renderColumnsBar() - }; + +this.root.renderRowsBar(); }; private handleScroll = () => { const rect = this.getViewportBoundlingRect(); @@ -174,7 +178,8 @@ export class Scroller { this.root.renderSheet(); this.root.renderColumnsBar() - }; + +this.root.renderRowsBar(); }; public getViewportBoundlingRect(): ViewportRect { const { scrollTop, scrollLeft } = this.element; diff --git a/src/components/table.ts b/src/components/table.ts index f840f9b..90773da 100644 --- a/src/components/table.ts +++ b/src/components/table.ts @@ -16,7 +16,7 @@ export class Table { changeElementSizes(sizes: ViewProperties) { const { height, width } = sizes; - this.element.style.width = width + "px"; + this.element.style.width = width + this.root.rowsBarWidth + "px"; this.element.style.height = height + this.root.columnsBarHeight + "px"; } } diff --git a/src/components/toolbar.ts b/src/components/toolbar.ts index fef13a9..5a21290 100644 --- a/src/components/toolbar.ts +++ b/src/components/toolbar.ts @@ -3,6 +3,7 @@ import Spreadsheet, { CSS_PREFIX } from "../main"; export class Toolbar { element: HTMLDivElement; root: Spreadsheet; + height: number = 0 constructor(root: Spreadsheet) { this.root = root; const toolbarElement = document.createElement("div"); diff --git a/src/main.ts b/src/main.ts index 7f84631..a57c6f5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -20,6 +20,7 @@ import { Cache, CachedColumn, CachedRow } from "./modules/cache"; import { Row } from "./modules/row"; import { Column } from "./modules/column"; import { ColumnsBar } from "./components/columnsBar"; +import { RowsBar } from "./components/rowsBar"; /* ! Component structure @@ -44,6 +45,7 @@ export default class Spreadsheet { private table: Table; private scroller: Scroller; private toolbar: Toolbar; + private rowsBar: RowsBar private columnsBar: ColumnsBar private sheet: Sheet; private editor: Editor; @@ -69,6 +71,7 @@ export default class Spreadsheet { this.config = new Config(config); + this.rowsBar = new RowsBar(this) this.columnsBar = new ColumnsBar(this) this.sheet = new Sheet(this); this.table = new Table(this); @@ -85,9 +88,28 @@ export default class Spreadsheet { this.data = data; this.styles = new Styles(); this.buildComponent(); + this.setElementsPositions() this.appendTableToTarget(target); this.renderSheet(); this.renderColumnsBar() + this.renderRowsBar() + } + + private setRowsBarPosition() { + const top = this.columnsBar.height + this.toolbar.height + const left = 0 + this.rowsBar.setElementPosition(top, left) + } + private setColumnsBarPosition() { + const top = this.toolbar.height + const left = this.rowsBar.width + console.log(top,left) + this.columnsBar.setElementPosition(top, left) + } + + private setElementsPositions() { + this.setRowsBarPosition() + this.setColumnsBarPosition() } private getInitialCache(): Cache { @@ -128,12 +150,14 @@ export default class Spreadsheet { private buildComponent(): void { const content = document.createElement("div"); //* Abstract content.style.top = this.columnsBarHeight + 'px' + content.style.left = this.rowsBarWidth + 'px' content.appendChild(this.sheet.element); content.classList.add(CSS_PREFIX + "content"); this.table.element.appendChild(this.toolbar.element); + this.table.element.appendChild(this.rowsBar.element) this.table.element.appendChild(this.columnsBar.element) this.table.element.appendChild(content); this.table.element.appendChild(this.scroller.element); @@ -178,6 +202,14 @@ export default class Spreadsheet { return this.columnsBar.height } + get rowsBarWidth() { + return this.rowsBar.width + } + + get toolbarHeight() { + return this.toolbar.height + } + /** Focusing on interactive part of spreadsheet */ focusTable() { this.scroller.element.focus(); @@ -257,6 +289,10 @@ export default class Spreadsheet { this.columnsBar.renderBar() } + renderRowsBar() { + this.rowsBar.renderBar() + } + renderCell(row: number, col: number) { this.data[row][col].render(this); } diff --git a/src/modules/renderBox.ts b/src/modules/renderBox.ts index 9c644ef..e7b2062 100644 --- a/src/modules/renderBox.ts +++ b/src/modules/renderBox.ts @@ -6,6 +6,7 @@ export class RenderBox { y: number; width: number; height: number; + constructor(config: Config, cellPosition: Position) { this.x = this.getXCoord(cellPosition.column, config); this.y = this.getYCoord(cellPosition.row, config);