Added and configured logic implementation of SCROLLER element
Scroller is interactive element. Every event will dispatch here.
This commit is contained in:
parent
d1ba4fe685
commit
25e698a658
|
|
@ -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'
|
||||
}
|
||||
}
|
||||
|
|
@ -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})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
42
src/main.ts
42
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
|
||||
<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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
Loading…
Reference in New Issue