From 25e698a658a47c6f41cc60213253ac419d1ff8f5 Mon Sep 17 00:00:00 2001 From: Eugene Date: Thu, 20 Jul 2023 16:57:50 +0300 Subject: [PATCH] Added and configured logic implementation of SCROLLER element Scroller is interactive element. Every event will dispatch here. --- src/components/scroller.ts | 67 +++++++++++++++++++++++++++++++++++--- src/components/sheet.ts | 17 +++++++++- src/main.ts | 42 +++++++++++++++--------- src/modules/cell.ts | 13 +++++--- src/modules/renderBox.ts | 33 +++++++++++++++++++ src/scss/_spreadsheet.scss | 20 ++++++++++++ 6 files changed, 166 insertions(+), 26 deletions(-) create mode 100644 src/modules/renderBox.ts diff --git a/src/components/scroller.ts b/src/components/scroller.ts index 88f2f13..a09dcca 100644 --- a/src/components/scroller.ts +++ b/src/components/scroller.ts @@ -2,18 +2,75 @@ import { Spreadsheet } from "../main" export class Scroller { element: HTMLDivElement - root: Spreadsheet + private verticalScroller: HTMLDivElement + private horizontalScroller: HTMLDivElement + private root: Spreadsheet + constructor(root: Spreadsheet) { this.root = root - const scroller = document.createElement('div') - scroller.classList.add('scroller') + const {horizontalScroller, scroller, verticalScroller} = this.buildComponent() this.element = scroller + this.verticalScroller = verticalScroller + this.horizontalScroller = horizontalScroller + + this.element.style.height = this.root.config.view.height + 'px' + this.element.style.width = this.root.config.view.width + 'px' + + this.updateScrollerSize() //* Init size set } + + buildComponent() { + const scroller = document.createElement('div') + const verticalScroller = document.createElement('div') + const horizontalScroller = document.createElement('div') + const groupScrollers = document.createElement('div') + const stack = document.createElement('div') + + verticalScroller.style.width = '0px' + verticalScroller.style.pointerEvents = 'none' + + horizontalScroller.style.pointerEvents = 'none' + + groupScrollers.style.display = 'flex' + + stack.appendChild(verticalScroller) + stack.appendChild(horizontalScroller) + groupScrollers.appendChild(stack) + this.verticalScroller = verticalScroller + this.horizontalScroller = horizontalScroller + scroller.appendChild(groupScrollers) + scroller.classList.add('scroller') + + return {scroller, verticalScroller, horizontalScroller} + } + + getActualHeight() { + return this.root.config.rows.reduce((acc, curr) => { + acc += curr.height + return acc + }, 0) + } + + getActualWidth() { + return this.root.config.columns.reduce((acc, curr) => { + acc += curr.width + return acc + }, 0) + } + + updateScrollerSize() { + const totalHeight = this.getActualHeight() + const totalWidth = this.getActualWidth() + + this.setScrollerHeight(totalHeight) + this.setScrollerWidth(totalWidth) + } + setScrollerHeight(height: number) { - this.element.style.height = height + 'px' + this.verticalScroller.style.height = height + 'px' } setScrollerWidth(width: number) { - this.element.style.width = width + 'px' + 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 2a0506b..75722e2 100644 --- a/src/components/sheet.ts +++ b/src/components/sheet.ts @@ -1,4 +1,5 @@ import { Spreadsheet } from "../main" +import { Position } from "../modules/cell" /** * Display (CANVAS) element where cells render @@ -11,11 +12,24 @@ export class Sheet { this.root = root const canvas = document.createElement('canvas') canvas.classList.add('sheet') + + //* Set up canvas sizes based on provided root config + canvas.height = this.root.config.view.height + 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' + this.element = canvas const ctx = this.element.getContext('2d') if(!ctx) throw new Error('Enable hardware acceleration') this.ctx = ctx + + } + + renderCell(position: Position) { + const {column, row} = position + this.root.data[row][column].render(this.root) } renderSheet() { @@ -25,8 +39,9 @@ export class Sheet { for(let row = 0; row <= lastRowIdx; row++) { for(let col = 0; col <= lastColIdx; col++ ) { - this.root.data[row][col].render(this.root.ctx, this.root.config) + this.renderCell({column: col, row}) } } } + } \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index fabb9ec..5d5faf5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -5,13 +5,13 @@ import { Sheet } from "./components/sheet"; import { Table } from "./components/table"; import { Toolbar } from "./components/toolbar"; import { Cell } from "./modules/cell"; -import { Config, ConfigProperties } from "./modules/config"; +import { Config, ViewProperties } from "./modules/config"; import { Styles } from "./modules/styles"; import './scss/main.scss' -import { createSampleConfig, createSampleData, makeSpreadsheetConfigAndData } from "./utils/createData"; +import { createSampleConfig, createSampleData } from "./utils/createData"; /* - * Component structure + ! Component structure //* Abstract @@ -22,6 +22,11 @@ import { createSampleConfig, createSampleData, makeSpreadsheetConfigAndData } fr
*/ +interface SpreadsheetConstructorProperties { + config?: Omit // Not optional. + view?: ViewProperties +} + export class Spreadsheet { private table: Table private scroller: Scroller @@ -33,23 +38,23 @@ export class Spreadsheet { public config: Config public data: Cell[][] - - - constructor(target: string | HTMLElement, config?: ConfigProperties) { + constructor(target: string | HTMLElement, props?: SpreadsheetConstructorProperties) { + const config = createSampleConfig(40, 40) + if(props?.view) { + config.view = props.view + } + + this.config = new Config(config) + this.sheet = new Sheet(this) const data = createSampleData(40, 40) - this.data = data - - this.config = new Config(config ?? createSampleConfig(40, 40)) - - this.styles = new Styles() - this.table = new Table(this) this.scroller = new Scroller(this) this.toolbar = new Toolbar(this) this.header = new Header(this) - this.sheet = new Sheet(this) this.editor = new Editor(this) - + + this.data = data + this.styles = new Styles() this.buildComponent() this.appendTableToTarget(target) } @@ -90,12 +95,17 @@ export class Spreadsheet { } renderCell(row: number, col: number) { - this.data[row][col].render(this.ctx, this.config) + this.data[row][col].render(this) } } -const spreadsheet = new Spreadsheet('#spreadsheet') +const spreadsheet = new Spreadsheet('#spreadsheet', { + view: { + height: 400, + width: 1200 + }, +}) spreadsheet.renderSheet() console.log(spreadsheet) diff --git a/src/modules/cell.ts b/src/modules/cell.ts index 095e603..1d2d494 100644 --- a/src/modules/cell.ts +++ b/src/modules/cell.ts @@ -1,4 +1,5 @@ -import { Config } from "./config" +import { Spreadsheet } from "../main" +import { RenderBox } from "./renderBox" export type CellConstructorProps = { value: string @@ -29,8 +30,12 @@ export class Cell { this.position = props.position } - render(ctx: CanvasRenderingContext2D, config: Config) { - ctx.fillStyle = 'black' - ctx.fillRect(0, 0, 20, 20) + render(root: Spreadsheet) { + const {height, width, x, y} = new RenderBox(root.config, this.position) + const { ctx } = root + ctx.fillStyle = 'white' + ctx.strokeStyle = 'black' + ctx.fillRect(x + 1, y + 1, width - 1, height - 1) + ctx.strokeRect(x, y, width, height) } } \ No newline at end of file diff --git a/src/modules/renderBox.ts b/src/modules/renderBox.ts new file mode 100644 index 0000000..a9d70cc --- /dev/null +++ b/src/modules/renderBox.ts @@ -0,0 +1,33 @@ +import { Position } from "./cell"; +import { Config } from "./config"; + +export class RenderBox { + x: number + 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) + this.width = config.columns[cellPosition.column].width + this.height = config.rows[cellPosition.row].height + } + + private getXCoord(column: number, config: Config): number { + let x = 0; + + for(let i = 0; i < column; i++) { + x += config.columns[i].width + } + + return x + } + + private getYCoord(row: number, config: Config): number { + let y = 0 + for(let i = 0; i < row; i++) { + y += config.rows[i].height + } + return y + } +} \ No newline at end of file diff --git a/src/scss/_spreadsheet.scss b/src/scss/_spreadsheet.scss index e69de29..82563aa 100644 --- a/src/scss/_spreadsheet.scss +++ b/src/scss/_spreadsheet.scss @@ -0,0 +1,20 @@ +.content { + position: absolute; + top: 0; + left: 0; +} + +.spreadsheet_container { + isolation: isolate; +} + +.sheet{ + display: block; + contain: strict; +} + +.scroller { + overflow: scroll; + box-sizing: border-box; + transform: translateZ(0); +} \ No newline at end of file