Added selection calculating
Todo: Move listeners from scroller (handlers)
This commit is contained in:
parent
6df6413838
commit
b4aa4a4b67
|
|
@ -12,6 +12,8 @@ export class Scroller {
|
|||
private verticalScroller: HTMLDivElement
|
||||
private horizontalScroller: HTMLDivElement
|
||||
private root: Spreadsheet
|
||||
|
||||
private isSelecting = false
|
||||
|
||||
constructor(root: Spreadsheet) {
|
||||
this.root = root
|
||||
|
|
@ -26,16 +28,45 @@ export class Scroller {
|
|||
this.updateScrollerSize() //* Init size set
|
||||
|
||||
this.element.addEventListener('scroll', this.handleScroll)
|
||||
|
||||
this.element.addEventListener('mousedown', this.handleClick)
|
||||
this.element.addEventListener('mousemove', event => {
|
||||
if(!this.isSelecting) return;
|
||||
const {offsetX, offsetY} = event
|
||||
const lastSelectedCell = this.root.getCellByCoords(offsetX, offsetY)
|
||||
if(this.root.selection.selectedRange) {
|
||||
this.root.selection.selectedRange.to = lastSelectedCell
|
||||
}
|
||||
})
|
||||
this.element.addEventListener('mouseup', () => {
|
||||
this.isSelecting = false
|
||||
|
||||
console.log(this.root.selection)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
handleScroll = () => {
|
||||
private handleClick = (event: MouseEvent) => {
|
||||
const {offsetX, offsetY} = event
|
||||
const clickedCell = this.root.getCellByCoords(offsetX, offsetY)
|
||||
this.isSelecting = true
|
||||
this.root.selection.selectedRange = {
|
||||
from: clickedCell,
|
||||
to: clickedCell
|
||||
}
|
||||
this.root.selection.selectedCell = clickedCell
|
||||
|
||||
this.root.renderSheet()
|
||||
}
|
||||
|
||||
private handleScroll = () => {
|
||||
const rect = this.getViewportBoundlingRect()
|
||||
this.root.viewport.updateValues(rect)
|
||||
|
||||
this.root.renderSheet()
|
||||
}
|
||||
|
||||
getViewportBoundlingRect(): ViewportRect {
|
||||
public getViewportBoundlingRect(): ViewportRect {
|
||||
const { scrollTop, scrollLeft } = this.element
|
||||
const { height, width } = this.element.getBoundingClientRect()
|
||||
const bottom = scrollTop + height
|
||||
|
|
@ -49,7 +80,7 @@ export class Scroller {
|
|||
}
|
||||
}
|
||||
|
||||
buildComponent() {
|
||||
private buildComponent() {
|
||||
const scroller = document.createElement('div')
|
||||
const verticalScroller = document.createElement('div')
|
||||
const horizontalScroller = document.createElement('div')
|
||||
|
|
@ -74,14 +105,14 @@ export class Scroller {
|
|||
return { scroller, verticalScroller, horizontalScroller }
|
||||
}
|
||||
|
||||
getActualHeight() {
|
||||
private getActualHeight() {
|
||||
return this.root.config.rows.reduce((acc, curr) => {
|
||||
acc += curr.height
|
||||
return acc
|
||||
}, 0)
|
||||
}
|
||||
|
||||
getActualWidth() {
|
||||
private getActualWidth() {
|
||||
return this.root.config.columns.reduce((acc, curr) => {
|
||||
acc += curr.width
|
||||
return acc
|
||||
|
|
@ -96,11 +127,11 @@ export class Scroller {
|
|||
this.setScrollerWidth(totalWidth)
|
||||
}
|
||||
|
||||
setScrollerHeight(height: number) {
|
||||
private setScrollerHeight(height: number) {
|
||||
this.verticalScroller.style.height = height + 'px'
|
||||
}
|
||||
|
||||
setScrollerWidth(width: number) {
|
||||
private setScrollerWidth(width: number) {
|
||||
this.horizontalScroller.style.width = width + 'px'
|
||||
}
|
||||
}
|
||||
|
|
@ -27,6 +27,26 @@ export class Sheet {
|
|||
|
||||
}
|
||||
|
||||
getCellByCoords(x: number, y: number): Position {
|
||||
let row = 0;
|
||||
let height = 0
|
||||
while(height <= y) {
|
||||
height += this.root.config.rows[row].height
|
||||
if(height >= y) break;
|
||||
row++;
|
||||
}
|
||||
|
||||
let col = 0;
|
||||
let width = 0;
|
||||
while(width <= x) {
|
||||
width += this.root.config.columns[col].width
|
||||
if(width >= x) break;
|
||||
col++;
|
||||
}
|
||||
|
||||
return new Position(row, col)
|
||||
}
|
||||
|
||||
renderCell(position: Position) {
|
||||
const {column, row} = position
|
||||
this.root.data[row][column].render(this.root)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { Table } from "./components/table";
|
|||
import { Toolbar } from "./components/toolbar";
|
||||
import { Cell } from "./modules/cell";
|
||||
import { Config, ViewProperties } from "./modules/config";
|
||||
import { Selection } from "./modules/selection";
|
||||
import { Styles } from "./modules/styles";
|
||||
import { Viewport } from "./modules/viewport";
|
||||
import './scss/main.scss'
|
||||
|
|
@ -39,6 +40,7 @@ export class Spreadsheet {
|
|||
public config: Config
|
||||
public data: Cell[][]
|
||||
public viewport: Viewport
|
||||
public selection: Selection
|
||||
|
||||
constructor(target: string | HTMLElement, props?: SpreadsheetConstructorProperties) {
|
||||
const config = createSampleConfig(750, 750)
|
||||
|
|
@ -55,6 +57,7 @@ export class Spreadsheet {
|
|||
this.header = new Header(this)
|
||||
this.editor = new Editor(this)
|
||||
this.viewport = new Viewport(this, this.scroller.getViewportBoundlingRect())
|
||||
this.selection = new Selection()
|
||||
|
||||
|
||||
this.data = data
|
||||
|
|
@ -94,6 +97,10 @@ export class Spreadsheet {
|
|||
return this.config.view
|
||||
}
|
||||
|
||||
getCellByCoords(x: number, y: number) {
|
||||
return this.sheet.getCellByCoords(x, y)
|
||||
}
|
||||
|
||||
renderSheet() {
|
||||
this.sheet.renderSheet()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,18 +34,19 @@ export class Cell {
|
|||
let {height, width, x, y} = new RenderBox(root.config, this.position)
|
||||
const { ctx } = root
|
||||
|
||||
const isCellSelected = (root.selection.selectedCell?.row === this.position.row && root.selection.selectedCell.column === this.position.column)
|
||||
y -= root.viewport.top
|
||||
x -= root.viewport.left
|
||||
|
||||
ctx.clearRect(x, y, width, height)
|
||||
ctx.fillStyle = 'white'
|
||||
ctx.fillStyle = isCellSelected ? 'red' : 'white'
|
||||
ctx.strokeStyle = 'black'
|
||||
ctx.fillRect(x + 1, y + 1, width - 1, height - 1)
|
||||
ctx.fillRect(x, y, width - 1, height - 1)
|
||||
ctx.strokeRect(x, y, width, height)
|
||||
|
||||
ctx.fillStyle = 'black'
|
||||
ctx.textAlign = 'left'
|
||||
ctx.font = '16px Arial'
|
||||
ctx.font = `16px Arial`
|
||||
ctx.textBaseline = 'middle'
|
||||
ctx.fillText(this.displayValue, x + 2, y + height / 2, width)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ export class RenderBox {
|
|||
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
|
||||
|
|
@ -16,7 +17,7 @@ export class RenderBox {
|
|||
private getXCoord(column: number, config: Config): number {
|
||||
let x = 0;
|
||||
|
||||
for(let i = 0; i < column; i++) {
|
||||
for (let i = 0; i < column; i++) {
|
||||
x += config.columns[i].width
|
||||
}
|
||||
|
||||
|
|
@ -25,7 +26,7 @@ export class RenderBox {
|
|||
|
||||
private getYCoord(row: number, config: Config): number {
|
||||
let y = 0
|
||||
for(let i = 0; i < row; i++) {
|
||||
for (let i = 0; i < row; i++) {
|
||||
y += config.rows[i].height
|
||||
}
|
||||
return y
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
|
||||
|
||||
.content {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
|
@ -5,7 +7,9 @@
|
|||
}
|
||||
|
||||
.spreadsheet_container {
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
border: 2px solid black;
|
||||
}
|
||||
|
||||
.sheet{
|
||||
|
|
|
|||
Loading…
Reference in New Issue