Added and configured logic implementation of SCROLLER element

Scroller is interactive element.
Every event will dispatch here.
This commit is contained in:
Eugene 2023-07-20 16:57:50 +03:00
parent d1ba4fe685
commit 25e698a658
6 changed files with 166 additions and 26 deletions

View File

@ -2,18 +2,75 @@ import { Spreadsheet } from "../main"
export class Scroller { export class Scroller {
element: HTMLDivElement element: HTMLDivElement
root: Spreadsheet private verticalScroller: HTMLDivElement
private horizontalScroller: HTMLDivElement
private root: Spreadsheet
constructor(root: Spreadsheet) { constructor(root: Spreadsheet) {
this.root = root this.root = root
const scroller = document.createElement('div') const {horizontalScroller, scroller, verticalScroller} = this.buildComponent()
scroller.classList.add('scroller')
this.element = scroller 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) { setScrollerHeight(height: number) {
this.element.style.height = height + 'px' this.verticalScroller.style.height = height + 'px'
} }
setScrollerWidth(width: number) { setScrollerWidth(width: number) {
this.element.style.width = width + 'px' this.horizontalScroller.style.width = width + 'px'
} }
} }

View File

@ -1,4 +1,5 @@
import { Spreadsheet } from "../main" import { Spreadsheet } from "../main"
import { Position } from "../modules/cell"
/** /**
* Display (CANVAS) element where cells render * Display (CANVAS) element where cells render
@ -11,11 +12,24 @@ export class Sheet {
this.root = root this.root = root
const canvas = document.createElement('canvas') const canvas = document.createElement('canvas')
canvas.classList.add('sheet') 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 this.element = canvas
const ctx = this.element.getContext('2d') const ctx = this.element.getContext('2d')
if(!ctx) throw new Error('Enable hardware acceleration') if(!ctx) throw new Error('Enable hardware acceleration')
this.ctx = ctx this.ctx = ctx
}
renderCell(position: Position) {
const {column, row} = position
this.root.data[row][column].render(this.root)
} }
renderSheet() { renderSheet() {
@ -25,8 +39,9 @@ export class Sheet {
for(let row = 0; row <= lastRowIdx; row++) { for(let row = 0; row <= lastRowIdx; row++) {
for(let col = 0; col <= lastColIdx; col++ ) { for(let col = 0; col <= lastColIdx; col++ ) {
this.root.data[row][col].render(this.root.ctx, this.root.config) this.renderCell({column: col, row})
} }
} }
} }
} }

View File

@ -5,13 +5,13 @@ import { Sheet } from "./components/sheet";
import { Table } from "./components/table"; import { Table } from "./components/table";
import { Toolbar } from "./components/toolbar"; import { Toolbar } from "./components/toolbar";
import { Cell } from "./modules/cell"; import { Cell } from "./modules/cell";
import { Config, ConfigProperties } from "./modules/config"; import { Config, ViewProperties } from "./modules/config";
import { Styles } from "./modules/styles"; import { Styles } from "./modules/styles";
import './scss/main.scss' import './scss/main.scss'
import { createSampleConfig, createSampleData, makeSpreadsheetConfigAndData } from "./utils/createData"; import { createSampleConfig, createSampleData } from "./utils/createData";
/* /*
* Component structure ! Component structure
<Table> <Table>
<Toolbar /> <Toolbar />
<Content> //* Abstract <Content> //* Abstract
@ -22,6 +22,11 @@ import { createSampleConfig, createSampleData, makeSpreadsheetConfigAndData } fr
</Table> </Table>
*/ */
interface SpreadsheetConstructorProperties {
config?: Omit<Config, 'view'> // Not optional.
view?: ViewProperties
}
export class Spreadsheet { export class Spreadsheet {
private table: Table private table: Table
private scroller: Scroller private scroller: Scroller
@ -33,23 +38,23 @@ export class Spreadsheet {
public config: Config public config: Config
public data: Cell[][] public data: Cell[][]
constructor(target: string | HTMLElement, props?: SpreadsheetConstructorProperties) {
const config = createSampleConfig(40, 40)
constructor(target: string | HTMLElement, config?: ConfigProperties) { if(props?.view) {
config.view = props.view
}
this.config = new Config(config)
this.sheet = new Sheet(this)
const data = createSampleData(40, 40) 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.table = new Table(this)
this.scroller = new Scroller(this) this.scroller = new Scroller(this)
this.toolbar = new Toolbar(this) this.toolbar = new Toolbar(this)
this.header = new Header(this) this.header = new Header(this)
this.sheet = new Sheet(this)
this.editor = new Editor(this) this.editor = new Editor(this)
this.data = data
this.styles = new Styles()
this.buildComponent() this.buildComponent()
this.appendTableToTarget(target) this.appendTableToTarget(target)
} }
@ -90,12 +95,17 @@ export class Spreadsheet {
} }
renderCell(row: number, col: number) { 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() spreadsheet.renderSheet()
console.log(spreadsheet) console.log(spreadsheet)

View File

@ -1,4 +1,5 @@
import { Config } from "./config" import { Spreadsheet } from "../main"
import { RenderBox } from "./renderBox"
export type CellConstructorProps = { export type CellConstructorProps = {
value: string value: string
@ -29,8 +30,12 @@ export class Cell {
this.position = props.position this.position = props.position
} }
render(ctx: CanvasRenderingContext2D, config: Config) { render(root: Spreadsheet) {
ctx.fillStyle = 'black' const {height, width, x, y} = new RenderBox(root.config, this.position)
ctx.fillRect(0, 0, 20, 20) 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)
} }
} }

33
src/modules/renderBox.ts Normal file
View File

@ -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
}
}

View File

@ -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);
}