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 {
|
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'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
42
src/main.ts
42
src/main.ts
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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