diff --git a/README.md b/README.md index 599eaca..e62a248 100644 --- a/README.md +++ b/README.md @@ -36,4 +36,5 @@ function loadData() { - Formulas support - Selected cell depends cells highlight - Async formulas support -- Mutlisheets (?) \ No newline at end of file +- Mutlisheets (?) +- Copy & Paste support diff --git a/index.html b/index.html index 6227333..6461fdb 100644 --- a/index.html +++ b/index.html @@ -8,7 +8,6 @@
- diff --git a/src/components/columnsBar.ts b/src/components/columnsBar.ts new file mode 100644 index 0000000..66fd8d2 --- /dev/null +++ b/src/components/columnsBar.ts @@ -0,0 +1,93 @@ +import Spreadsheet, { RenderBox } from "../main" + +export class ColumnsBar { + public element: HTMLCanvasElement + private root: Spreadsheet + public height: number = 32 + public width: number + private resizerWidth = 2 + ctx: CanvasRenderingContext2D + + 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.width = this.root.viewProps.width + } + + 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 + } + + private isColumnSelected(column: number): boolean { + const { selectedCell, selectedRange } = this.root.selection + if (selectedCell && selectedCell.column === column) return true + if (selectedRange) { + const inRange = + column >= Math.min(selectedRange.from.column, selectedRange.to.column) && + column <= Math.max(selectedRange.from.column, selectedRange.to.column) + + return inRange + } + return false + } + + private renderText(column: number, renderBox: RenderBox) { + const { width, x } = renderBox + + this.ctx.fillStyle = 'black' + this.ctx.textAlign = 'center' + this.ctx.textBaseline = 'middle' + this.ctx.font = '16px Arial' + this.ctx.fillText(this.root.config.columns[column].title, x + (width / 2) - this.root.viewport.left, 0 + this.height / 2) + } + + private renderRect(column: number, renderBox: RenderBox) { + const { width, x } = renderBox + + const { selectedCell } = this.root.selection + + const isColSelected = this.isColumnSelected(column) + + console.log(selectedCell) + + this.ctx.fillStyle = isColSelected ? this.root.styles.cells.selectedBackground : 'white' + this.ctx.strokeStyle = 'black' + 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) { + const renderBox = new RenderBox(this.root.config, { + row: 0, + column: column + }) + + this.renderRect(column, renderBox) + this.renderText(column, renderBox) + } + + public renderBar() { + const lastColIdx = this.root.viewport.lastCol + 3; + const firstColIdx = this.root.viewport.firstCol; + + for (let col = firstColIdx; col <= lastColIdx; col++) { + this.renderSingleColumn(col) + } + } +} \ No newline at end of file diff --git a/src/components/editor.ts b/src/components/editor.ts index e765b3d..9c4cb9d 100644 --- a/src/components/editor.ts +++ b/src/components/editor.ts @@ -28,7 +28,7 @@ export class Editor { const cell = this.root.getCell(position); this.element.classList.remove("hide"); - this.element.style.top = y - this.root.viewport.top + "px"; + this.element.style.top = y - this.root.viewport.top + this.root.columnsBarHeight + "px"; this.element.style.left = x - this.root.viewport.left + "px"; this.element.style.width = width + "px"; this.element.style.height = height + "px"; diff --git a/src/components/header.ts b/src/components/header.ts deleted file mode 100644 index 71afc33..0000000 --- a/src/components/header.ts +++ /dev/null @@ -1,12 +0,0 @@ -import Spreadsheet from "../main"; - -export class Header { - element: HTMLHeadElement; - root: Spreadsheet; - constructor(root: Spreadsheet) { - this.root = root; - const headerElement = document.createElement("header"); - headerElement.classList.add(); - this.element = headerElement; - } -} diff --git a/src/components/scroller.ts b/src/components/scroller.ts index 446c4be..c4891d8 100644 --- a/src/components/scroller.ts +++ b/src/components/scroller.ts @@ -25,6 +25,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.tabIndex = -1; this.updateScrollerSize(); //* Init size set @@ -47,6 +48,7 @@ export class Scroller { this.root.selection.selectedRange.to = lastSelectedCell; } this.root.renderSheet(); + this.root.renderColumnsBar(); }; private handleMouseUp = () => { @@ -55,15 +57,16 @@ export class Scroller { if (this.root.selection.selectedRange) { if ( this.root.selection.selectedRange.from.row === - this.root.selection.selectedRange.to.row && + this.root.selection.selectedRange.to.row && this.root.selection.selectedRange.from.column === - this.root.selection.selectedRange.to.column + this.root.selection.selectedRange.to.column ) { this.root.selection.selectedRange = null; } } this.root.renderSheet(); + this.root.renderColumnsBar(); }; private handleDoubleClick = (event: MouseEvent) => { @@ -96,7 +99,7 @@ export class Scroller { if ( this.root.selection.selectedCell && this.root.selection.selectedCell.column < - this.root.config.columns.length - 1 + this.root.config.columns.length - 1 ) { this.root.selection.selectedCell.column += 1; this.root.renderSheet(); @@ -117,7 +120,7 @@ export class Scroller { if ( this.root.selection.selectedCell && this.root.selection.selectedCell.row < - this.root.config.rows.length - 1 + this.root.config.rows.length - 1 ) { this.root.selection.selectedCell.row += 1; this.root.renderSheet(); @@ -162,6 +165,7 @@ export class Scroller { this.root.selection.selectedCell = clickedCell; this.root.renderSheet(); + this.root.renderColumnsBar() }; private handleScroll = () => { @@ -169,6 +173,7 @@ export class Scroller { this.root.viewport.updateValues(rect); this.root.renderSheet(); + this.root.renderColumnsBar() }; public getViewportBoundlingRect(): ViewportRect { diff --git a/src/components/sheet.ts b/src/components/sheet.ts index a8280b4..e27717f 100644 --- a/src/components/sheet.ts +++ b/src/components/sheet.ts @@ -18,6 +18,7 @@ export class Sheet { canvas.width = this.root.config.view.width; canvas.style.width = this.root.config.view.width + "px"; canvas.style.height = this.root.config.view.height + "px"; + canvas.style.left = '0px' this.element = canvas; diff --git a/src/components/table.ts b/src/components/table.ts index 25d084e..f840f9b 100644 --- a/src/components/table.ts +++ b/src/components/table.ts @@ -17,6 +17,6 @@ export class Table { changeElementSizes(sizes: ViewProperties) { const { height, width } = sizes; this.element.style.width = width + "px"; - this.element.style.height = height + "px"; + this.element.style.height = height + this.root.columnsBarHeight + "px"; } } diff --git a/src/index.ts b/src/index.ts index e95ea71..9d6bf4b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,9 +6,6 @@ const loadButton = document.querySelector("#load_button"); if (!saveButton || !loadButton) throw new Error("LOST"); const sheet = new Spreadsheet("#spreadsheet"); -const sheet2 = new Spreadsheet("#spreadsheet_2"); - -console.log(sheet2); function saveDataToLS() { const serializableData = sheet.serializeData(); @@ -35,3 +32,19 @@ sheet.changeCellStyles( selectedFontColor: "black", }, ); + + +setTimeout(() => { + const text = 'Test123' + + const cellPosition = { + column: 1, + row: 1 + } + + sheet.changeCellValues(cellPosition, { + displayValue: text, + resultValue: text, + value: text + }) +}, 4000) \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index a30f59f..7f84631 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,4 @@ import { Editor } from "./components/editor"; -import { Header } from "./components/header"; import { Scroller } from "./components/scroller"; import { Sheet } from "./components/sheet"; import { Table } from "./components/table"; @@ -20,6 +19,7 @@ import { createSampleData } from "./utils/createData"; import { Cache, CachedColumn, CachedRow } from "./modules/cache"; import { Row } from "./modules/row"; import { Column } from "./modules/column"; +import { ColumnsBar } from "./components/columnsBar"; /* ! Component structure @@ -44,7 +44,7 @@ export default class Spreadsheet { private table: Table; private scroller: Scroller; private toolbar: Toolbar; - private header: Header; + private columnsBar: ColumnsBar private sheet: Sheet; private editor: Editor; public styles: Styles; @@ -68,12 +68,12 @@ export default class Spreadsheet { } this.config = new Config(config); - this.sheet = new Sheet(this); + this.columnsBar = new ColumnsBar(this) + this.sheet = new Sheet(this); this.table = new Table(this); this.scroller = new Scroller(this); this.toolbar = new Toolbar(this); - this.header = new Header(this); this.editor = new Editor(this); this.cache = this.getInitialCache(); this.viewport = new Viewport( @@ -87,6 +87,7 @@ export default class Spreadsheet { this.buildComponent(); this.appendTableToTarget(target); this.renderSheet(); + this.renderColumnsBar() } private getInitialCache(): Cache { @@ -126,12 +127,14 @@ export default class Spreadsheet { private buildComponent(): void { const content = document.createElement("div"); //* Abstract - content.appendChild(this.header.element); + content.style.top = this.columnsBarHeight + 'px' + content.appendChild(this.sheet.element); content.classList.add(CSS_PREFIX + "content"); this.table.element.appendChild(this.toolbar.element); + this.table.element.appendChild(this.columnsBar.element) this.table.element.appendChild(content); this.table.element.appendChild(this.scroller.element); this.table.element.append(this.editor.element); @@ -171,6 +174,10 @@ export default class Spreadsheet { return this.config.view; } + get columnsBarHeight() { + return this.columnsBar.height + } + /** Focusing on interactive part of spreadsheet */ focusTable() { this.scroller.element.focus(); @@ -246,6 +253,10 @@ export default class Spreadsheet { this.sheet.renderSheet(); } + renderColumnsBar() { + this.columnsBar.renderBar() + } + renderCell(row: number, col: number) { this.data[row][col].render(this); } diff --git a/src/scss/_spreadsheet.scss b/src/scss/_spreadsheet.scss index d7fb8fc..eb83c0d 100644 --- a/src/scss/_spreadsheet.scss +++ b/src/scss/_spreadsheet.scss @@ -2,8 +2,6 @@ $css_prefix: "modern_sc_"; .#{$css_prefix}content { position: absolute; - top: 0; - left: 0; } .#{$css_prefix}spreadsheet_container { @@ -18,6 +16,7 @@ $css_prefix: "modern_sc_"; } .#{$css_prefix}scroller { + position: absolute; overflow: scroll; box-sizing: border-box; transform: translateZ(0);