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 {
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'
}
}

View File

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

View File

@ -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
<Table>
<Toolbar />
<Content> //* Abstract
@ -22,6 +22,11 @@ import { createSampleConfig, createSampleData, makeSpreadsheetConfigAndData } fr
</Table>
*/
interface SpreadsheetConstructorProperties {
config?: Omit<Config, 'view'> // 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)

View File

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

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