Added full support of rendering table
Todo: test with resize
This commit is contained in:
parent
25e698a658
commit
ee85d771a4
|
|
@ -1,5 +1,12 @@
|
||||||
import { Spreadsheet } from "../main"
|
import { Spreadsheet } from "../main"
|
||||||
|
|
||||||
|
export interface ViewportRect {
|
||||||
|
top: number
|
||||||
|
left: number
|
||||||
|
right: number
|
||||||
|
bottom: number
|
||||||
|
}
|
||||||
|
|
||||||
export class Scroller {
|
export class Scroller {
|
||||||
element: HTMLDivElement
|
element: HTMLDivElement
|
||||||
private verticalScroller: HTMLDivElement
|
private verticalScroller: HTMLDivElement
|
||||||
|
|
@ -8,7 +15,7 @@ export class Scroller {
|
||||||
|
|
||||||
constructor(root: Spreadsheet) {
|
constructor(root: Spreadsheet) {
|
||||||
this.root = root
|
this.root = root
|
||||||
const {horizontalScroller, scroller, verticalScroller} = this.buildComponent()
|
const { horizontalScroller, scroller, verticalScroller } = this.buildComponent()
|
||||||
this.element = scroller
|
this.element = scroller
|
||||||
this.verticalScroller = verticalScroller
|
this.verticalScroller = verticalScroller
|
||||||
this.horizontalScroller = horizontalScroller
|
this.horizontalScroller = horizontalScroller
|
||||||
|
|
@ -17,6 +24,29 @@ export class Scroller {
|
||||||
this.element.style.width = this.root.config.view.width + 'px'
|
this.element.style.width = this.root.config.view.width + 'px'
|
||||||
|
|
||||||
this.updateScrollerSize() //* Init size set
|
this.updateScrollerSize() //* Init size set
|
||||||
|
|
||||||
|
this.element.addEventListener('scroll', this.handleScroll)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleScroll = () => {
|
||||||
|
const rect = this.getViewportBoundlingRect()
|
||||||
|
this.root.viewport.updateValues(rect)
|
||||||
|
|
||||||
|
this.root.renderSheet()
|
||||||
|
}
|
||||||
|
|
||||||
|
getViewportBoundlingRect(): ViewportRect {
|
||||||
|
const { scrollTop, scrollLeft } = this.element
|
||||||
|
const { height, width } = this.element.getBoundingClientRect()
|
||||||
|
const bottom = scrollTop + height
|
||||||
|
const right = scrollLeft + width
|
||||||
|
|
||||||
|
return {
|
||||||
|
top: scrollTop,
|
||||||
|
left: scrollLeft,
|
||||||
|
bottom,
|
||||||
|
right
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildComponent() {
|
buildComponent() {
|
||||||
|
|
@ -30,18 +60,18 @@ export class Scroller {
|
||||||
verticalScroller.style.pointerEvents = 'none'
|
verticalScroller.style.pointerEvents = 'none'
|
||||||
|
|
||||||
horizontalScroller.style.pointerEvents = 'none'
|
horizontalScroller.style.pointerEvents = 'none'
|
||||||
|
|
||||||
groupScrollers.style.display = 'flex'
|
groupScrollers.style.display = 'flex'
|
||||||
|
|
||||||
stack.appendChild(verticalScroller)
|
stack.appendChild(verticalScroller)
|
||||||
stack.appendChild(horizontalScroller)
|
stack.appendChild(horizontalScroller)
|
||||||
groupScrollers.appendChild(stack)
|
groupScrollers.appendChild(stack)
|
||||||
this.verticalScroller = verticalScroller
|
this.verticalScroller = verticalScroller
|
||||||
this.horizontalScroller = horizontalScroller
|
this.horizontalScroller = horizontalScroller
|
||||||
scroller.appendChild(groupScrollers)
|
scroller.appendChild(groupScrollers)
|
||||||
scroller.classList.add('scroller')
|
scroller.classList.add('scroller')
|
||||||
|
|
||||||
return {scroller, verticalScroller, horizontalScroller}
|
return { scroller, verticalScroller, horizontalScroller }
|
||||||
}
|
}
|
||||||
|
|
||||||
getActualHeight() {
|
getActualHeight() {
|
||||||
|
|
|
||||||
|
|
@ -33,15 +33,27 @@ export class Sheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSheet() {
|
renderSheet() {
|
||||||
const {columns, rows} = this.root.config
|
const firstRowIdx = this.root.viewport.firstRow
|
||||||
const lastColIdx = columns.length - 1
|
const lastColIdx = this.root.viewport.lastCol + 3
|
||||||
const lastRowIdx = rows.length - 1
|
const lastRowIdx = this.root.viewport.lastRow + 3
|
||||||
|
const firstColIdx = this.root.viewport.firstCol
|
||||||
|
|
||||||
|
console.log()
|
||||||
|
|
||||||
|
let rowsCount = 0
|
||||||
|
|
||||||
|
for(let row = firstRowIdx; row <= lastRowIdx; row++) {
|
||||||
|
|
||||||
|
for(let col = firstColIdx; col <= lastColIdx; col++ ) {
|
||||||
|
if(!this.root.config.columns[col] || !this.root.config.rows[row]) break; //* Prevent read undefined
|
||||||
|
|
||||||
for(let row = 0; row <= lastRowIdx; row++) {
|
|
||||||
for(let col = 0; col <= lastColIdx; col++ ) {
|
|
||||||
this.renderCell({column: col, row})
|
this.renderCell({column: col, row})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rowsCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(`Rendered ${rowsCount} rows!`)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
export class Viewport {
|
|
||||||
|
|
||||||
}
|
|
||||||
10
src/main.ts
10
src/main.ts
|
|
@ -7,6 +7,7 @@ import { Toolbar } from "./components/toolbar";
|
||||||
import { Cell } from "./modules/cell";
|
import { Cell } from "./modules/cell";
|
||||||
import { Config, ViewProperties } from "./modules/config";
|
import { Config, ViewProperties } from "./modules/config";
|
||||||
import { Styles } from "./modules/styles";
|
import { Styles } from "./modules/styles";
|
||||||
|
import { Viewport } from "./modules/viewport";
|
||||||
import './scss/main.scss'
|
import './scss/main.scss'
|
||||||
import { createSampleConfig, createSampleData } from "./utils/createData";
|
import { createSampleConfig, createSampleData } from "./utils/createData";
|
||||||
|
|
||||||
|
|
@ -37,22 +38,25 @@ export class Spreadsheet {
|
||||||
public styles: Styles
|
public styles: Styles
|
||||||
public config: Config
|
public config: Config
|
||||||
public data: Cell[][]
|
public data: Cell[][]
|
||||||
|
public viewport: Viewport
|
||||||
|
|
||||||
constructor(target: string | HTMLElement, props?: SpreadsheetConstructorProperties) {
|
constructor(target: string | HTMLElement, props?: SpreadsheetConstructorProperties) {
|
||||||
const config = createSampleConfig(40, 40)
|
const config = createSampleConfig(150, 150)
|
||||||
if(props?.view) {
|
if(props?.view) {
|
||||||
config.view = props.view
|
config.view = props.view
|
||||||
}
|
}
|
||||||
|
|
||||||
this.config = new Config(config)
|
this.config = new Config(config)
|
||||||
this.sheet = new Sheet(this)
|
this.sheet = new Sheet(this)
|
||||||
const data = createSampleData(40, 40)
|
const data = createSampleData(150, 150)
|
||||||
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.editor = new Editor(this)
|
this.editor = new Editor(this)
|
||||||
|
this.viewport = new Viewport(this, this.scroller.getViewportBoundlingRect())
|
||||||
|
|
||||||
|
|
||||||
this.data = data
|
this.data = data
|
||||||
this.styles = new Styles()
|
this.styles = new Styles()
|
||||||
this.buildComponent()
|
this.buildComponent()
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,22 @@ export class Cell {
|
||||||
}
|
}
|
||||||
|
|
||||||
render(root: Spreadsheet) {
|
render(root: Spreadsheet) {
|
||||||
const {height, width, x, y} = new RenderBox(root.config, this.position)
|
let {height, width, x, y} = new RenderBox(root.config, this.position)
|
||||||
const { ctx } = root
|
const { ctx } = root
|
||||||
|
|
||||||
|
y -= root.viewport.top
|
||||||
|
x -= root.viewport.left
|
||||||
|
|
||||||
|
ctx.clearRect(x, y, width, height)
|
||||||
ctx.fillStyle = 'white'
|
ctx.fillStyle = 'white'
|
||||||
ctx.strokeStyle = 'black'
|
ctx.strokeStyle = 'black'
|
||||||
ctx.fillRect(x + 1, y + 1, width - 1, height - 1)
|
ctx.fillRect(x + 1, y + 1, width - 1, height - 1)
|
||||||
ctx.strokeRect(x, y, width, height)
|
ctx.strokeRect(x, y, width, height)
|
||||||
|
|
||||||
|
ctx.fillStyle = 'black'
|
||||||
|
ctx.textAlign = 'left'
|
||||||
|
ctx.font = '16px Arial'
|
||||||
|
ctx.textBaseline = 'middle'
|
||||||
|
ctx.fillText(this.displayValue, x + 2, y + height / 2, width)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
import { Spreadsheet } from "../main"
|
||||||
|
|
||||||
|
export type ViewportConstructorProps = {
|
||||||
|
top: number
|
||||||
|
left: number
|
||||||
|
right: number
|
||||||
|
bottom: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Viewport {
|
||||||
|
root: Spreadsheet
|
||||||
|
|
||||||
|
top: number
|
||||||
|
left: number
|
||||||
|
right: number
|
||||||
|
bottom: number
|
||||||
|
|
||||||
|
firstRow: number
|
||||||
|
lastRow: number
|
||||||
|
firstCol: number
|
||||||
|
lastCol: number
|
||||||
|
|
||||||
|
constructor(root: Spreadsheet, props: ViewportConstructorProps) {
|
||||||
|
this.root = root
|
||||||
|
|
||||||
|
this.top = props.top
|
||||||
|
this.left = props.left
|
||||||
|
this.right = props.right
|
||||||
|
this.bottom = props.bottom
|
||||||
|
|
||||||
|
this.firstRow = this.getFirstRow()
|
||||||
|
this.lastCol = this.getFirstRow() //!Temp
|
||||||
|
this.firstCol = this.getFirstRow() //!Temp
|
||||||
|
this.lastRow = this.getLastRow()
|
||||||
|
|
||||||
|
this.updateValues({
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: this.root.viewProps.width,
|
||||||
|
bottom: this.root.viewProps.height
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
updateValues(props: ViewportConstructorProps) {
|
||||||
|
this.top = props.top
|
||||||
|
this.left = props.left
|
||||||
|
this.right = props.right
|
||||||
|
this.bottom = props.bottom
|
||||||
|
|
||||||
|
this.firstRow = this.getFirstRow()
|
||||||
|
this.lastRow = this.getLastRow()
|
||||||
|
this.firstCol = this.getFirstCol()
|
||||||
|
this.lastCol = this.getLastCol()
|
||||||
|
|
||||||
|
console.log({ first: this.firstCol, last: this.lastCol })
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get index of first row in viewport */
|
||||||
|
private getFirstRow(): number {
|
||||||
|
let rowIdx = 0
|
||||||
|
for (let idx = 0, currHeight = 0; currHeight <= this.top; idx++) {
|
||||||
|
currHeight += this.root.config.rows[idx].height
|
||||||
|
rowIdx = idx
|
||||||
|
}
|
||||||
|
return rowIdx
|
||||||
|
}
|
||||||
|
|
||||||
|
private getLastRow(): number {
|
||||||
|
let rowIdx = this.getFirstRow()
|
||||||
|
let height = this.top
|
||||||
|
|
||||||
|
while (height <= this.bottom) {
|
||||||
|
height += this.root.config.rows[rowIdx].height
|
||||||
|
if (height >= this.bottom) break;
|
||||||
|
rowIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rowIdx
|
||||||
|
}
|
||||||
|
|
||||||
|
private getFirstCol(): number {
|
||||||
|
let colIdx = 0;
|
||||||
|
let currWidth = 0
|
||||||
|
|
||||||
|
while (currWidth <= this.left) {
|
||||||
|
currWidth += this.root.config.columns[colIdx].width
|
||||||
|
if (currWidth >= this.left) break;
|
||||||
|
colIdx += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return colIdx
|
||||||
|
}
|
||||||
|
|
||||||
|
private getLastCol(): number {
|
||||||
|
let colIdx = this.getFirstCol()
|
||||||
|
let width = this.left
|
||||||
|
|
||||||
|
while (width <= this.right) {
|
||||||
|
width += this.root.config.columns[colIdx].width
|
||||||
|
if (width >= this.right) break;
|
||||||
|
colIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return colIdx
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue