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