Added new component ColumnsBar

Added render of ColumnsBar methods
Added selection condition render styling
This commit is contained in:
Eugene 2023-07-25 18:42:00 +03:00
parent 55e4eb0f70
commit ad69c4e01c
11 changed files with 139 additions and 30 deletions

View File

@ -41,4 +41,4 @@ function loadData() {
- Selected cell depends cells highlight - Selected cell depends cells highlight
- Async formulas support - Async formulas support
- Mutlisheets (?) - Mutlisheets (?)
- - Copy & Paste support

View File

@ -8,7 +8,6 @@
</head> </head>
<body> <body>
<div id="spreadsheet"></div> <div id="spreadsheet"></div>
<div id="spreadsheet_2"></div>
<button id="save_button">Save sheet</button> <button id="save_button">Save sheet</button>
<button id="load_button">Load sheet</button> <button id="load_button">Load sheet</button>
<script type="module" src="/src/index.ts"></script> <script type="module" src="/src/index.ts"></script>

View File

@ -0,0 +1,93 @@
import Spreadsheet, { RenderBox } from "../main"
export class ColumnsBar {
public element: HTMLCanvasElement
private root: Spreadsheet
public height: number = 32
public width: number
private resizerWidth = 2
ctx: CanvasRenderingContext2D
constructor(root: Spreadsheet) {
this.root = root
this.element = this.createElement()
const ctx = this.element.getContext('2d')
if (!ctx) throw new Error("Enable hardware acceleration");
this.ctx = ctx
this.width = this.root.viewProps.width
}
private createElement(): HTMLCanvasElement {
const element = document.createElement('canvas')
element.style.position = 'absolute'
element.style.top = '0'
element.style.left = '0'
element.style.height = this.height + 'px'
element.style.width = this.root.viewProps.width + 'px'
element.style.display = 'block'
element.width = this.root.viewProps.width
element.height = this.height
return element
}
private isColumnSelected(column: number): boolean {
const { selectedCell, selectedRange } = this.root.selection
if (selectedCell && selectedCell.column === column) return true
if (selectedRange) {
const inRange =
column >= Math.min(selectedRange.from.column, selectedRange.to.column) &&
column <= Math.max(selectedRange.from.column, selectedRange.to.column)
return inRange
}
return false
}
private renderText(column: number, renderBox: RenderBox) {
const { width, x } = renderBox
this.ctx.fillStyle = 'black'
this.ctx.textAlign = 'center'
this.ctx.textBaseline = 'middle'
this.ctx.font = '16px Arial'
this.ctx.fillText(this.root.config.columns[column].title, x + (width / 2) - this.root.viewport.left, 0 + this.height / 2)
}
private renderRect(column: number, renderBox: RenderBox) {
const { width, x } = renderBox
const { selectedCell } = this.root.selection
const isColSelected = this.isColumnSelected(column)
console.log(selectedCell)
this.ctx.fillStyle = isColSelected ? this.root.styles.cells.selectedBackground : 'white'
this.ctx.strokeStyle = 'black'
this.ctx.lineWidth = this.resizerWidth
this.ctx.fillRect(x - this.root.viewport.left - 1, 1, width - 1, this.height - 1)
this.ctx.strokeRect(x - this.root.viewport.left, 0, width, this.height)
}
private renderSingleColumn(column: number) {
const renderBox = new RenderBox(this.root.config, {
row: 0,
column: column
})
this.renderRect(column, renderBox)
this.renderText(column, renderBox)
}
public renderBar() {
const lastColIdx = this.root.viewport.lastCol + 3;
const firstColIdx = this.root.viewport.firstCol;
for (let col = firstColIdx; col <= lastColIdx; col++) {
this.renderSingleColumn(col)
}
}
}

View File

@ -28,7 +28,7 @@ export class Editor {
const cell = this.root.getCell(position); const cell = this.root.getCell(position);
this.element.classList.remove("hide"); this.element.classList.remove("hide");
this.element.style.top = y - this.root.viewport.top + "px"; this.element.style.top = y - this.root.viewport.top + this.root.columnsBarHeight + "px";
this.element.style.left = x - this.root.viewport.left + "px"; this.element.style.left = x - this.root.viewport.left + "px";
this.element.style.width = width + "px"; this.element.style.width = width + "px";
this.element.style.height = height + "px"; this.element.style.height = height + "px";

View File

@ -1,12 +0,0 @@
import Spreadsheet from "../main";
export class Header {
element: HTMLHeadElement;
root: Spreadsheet;
constructor(root: Spreadsheet) {
this.root = root;
const headerElement = document.createElement("header");
headerElement.classList.add();
this.element = headerElement;
}
}

View File

@ -25,6 +25,7 @@ export class Scroller {
this.element.style.height = this.root.config.view.height + "px"; this.element.style.height = this.root.config.view.height + "px";
this.element.style.width = this.root.config.view.width + "px"; this.element.style.width = this.root.config.view.width + "px";
this.element.style.top = this.root.columnsBarHeight + 'px'
this.element.tabIndex = -1; this.element.tabIndex = -1;
this.updateScrollerSize(); //* Init size set this.updateScrollerSize(); //* Init size set
@ -47,6 +48,7 @@ export class Scroller {
this.root.selection.selectedRange.to = lastSelectedCell; this.root.selection.selectedRange.to = lastSelectedCell;
} }
this.root.renderSheet(); this.root.renderSheet();
this.root.renderColumnsBar();
}; };
private handleMouseUp = () => { private handleMouseUp = () => {
@ -64,6 +66,7 @@ export class Scroller {
} }
this.root.renderSheet(); this.root.renderSheet();
this.root.renderColumnsBar();
}; };
private handleDoubleClick = (event: MouseEvent) => { private handleDoubleClick = (event: MouseEvent) => {
@ -162,6 +165,7 @@ export class Scroller {
this.root.selection.selectedCell = clickedCell; this.root.selection.selectedCell = clickedCell;
this.root.renderSheet(); this.root.renderSheet();
this.root.renderColumnsBar()
}; };
private handleScroll = () => { private handleScroll = () => {
@ -169,6 +173,7 @@ export class Scroller {
this.root.viewport.updateValues(rect); this.root.viewport.updateValues(rect);
this.root.renderSheet(); this.root.renderSheet();
this.root.renderColumnsBar()
}; };
public getViewportBoundlingRect(): ViewportRect { public getViewportBoundlingRect(): ViewportRect {

View File

@ -18,6 +18,7 @@ export class Sheet {
canvas.width = this.root.config.view.width; canvas.width = this.root.config.view.width;
canvas.style.width = this.root.config.view.width + "px"; canvas.style.width = this.root.config.view.width + "px";
canvas.style.height = this.root.config.view.height + "px"; canvas.style.height = this.root.config.view.height + "px";
canvas.style.left = '0px'
this.element = canvas; this.element = canvas;

View File

@ -17,6 +17,6 @@ export class Table {
changeElementSizes(sizes: ViewProperties) { changeElementSizes(sizes: ViewProperties) {
const { height, width } = sizes; const { height, width } = sizes;
this.element.style.width = width + "px"; this.element.style.width = width + "px";
this.element.style.height = height + "px"; this.element.style.height = height + this.root.columnsBarHeight + "px";
} }
} }

View File

@ -6,9 +6,6 @@ const loadButton = document.querySelector("#load_button");
if (!saveButton || !loadButton) throw new Error("LOST"); if (!saveButton || !loadButton) throw new Error("LOST");
const sheet = new Spreadsheet("#spreadsheet"); const sheet = new Spreadsheet("#spreadsheet");
const sheet2 = new Spreadsheet("#spreadsheet_2");
console.log(sheet2);
function saveDataToLS() { function saveDataToLS() {
const serializableData = sheet.serializeData(); const serializableData = sheet.serializeData();
@ -35,3 +32,19 @@ sheet.changeCellStyles(
selectedFontColor: "black", selectedFontColor: "black",
}, },
); );
setTimeout(() => {
const text = 'Test123'
const cellPosition = {
column: 1,
row: 1
}
sheet.changeCellValues(cellPosition, {
displayValue: text,
resultValue: text,
value: text
})
}, 4000)

View File

@ -1,5 +1,4 @@
import { Editor } from "./components/editor"; import { Editor } from "./components/editor";
import { Header } from "./components/header";
import { Scroller } from "./components/scroller"; import { Scroller } from "./components/scroller";
import { Sheet } from "./components/sheet"; import { Sheet } from "./components/sheet";
import { Table } from "./components/table"; import { Table } from "./components/table";
@ -20,6 +19,7 @@ import { createSampleData } from "./utils/createData";
import { Cache, CachedColumn, CachedRow } from "./modules/cache"; import { Cache, CachedColumn, CachedRow } from "./modules/cache";
import { Row } from "./modules/row"; import { Row } from "./modules/row";
import { Column } from "./modules/column"; import { Column } from "./modules/column";
import { ColumnsBar } from "./components/columnsBar";
/* /*
! Component structure ! Component structure
@ -44,7 +44,7 @@ export default class Spreadsheet {
private table: Table; private table: Table;
private scroller: Scroller; private scroller: Scroller;
private toolbar: Toolbar; private toolbar: Toolbar;
private header: Header; private columnsBar: ColumnsBar
private sheet: Sheet; private sheet: Sheet;
private editor: Editor; private editor: Editor;
public styles: Styles; public styles: Styles;
@ -68,12 +68,12 @@ export default class Spreadsheet {
} }
this.config = new Config(config); this.config = new Config(config);
this.sheet = new Sheet(this);
this.columnsBar = new ColumnsBar(this)
this.sheet = new Sheet(this);
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.editor = new Editor(this); this.editor = new Editor(this);
this.cache = this.getInitialCache(); this.cache = this.getInitialCache();
this.viewport = new Viewport( this.viewport = new Viewport(
@ -87,6 +87,7 @@ export default class Spreadsheet {
this.buildComponent(); this.buildComponent();
this.appendTableToTarget(target); this.appendTableToTarget(target);
this.renderSheet(); this.renderSheet();
this.renderColumnsBar()
} }
private getInitialCache(): Cache { private getInitialCache(): Cache {
@ -126,12 +127,14 @@ export default class Spreadsheet {
private buildComponent(): void { private buildComponent(): void {
const content = document.createElement("div"); //* Abstract const content = document.createElement("div"); //* Abstract
content.appendChild(this.header.element); content.style.top = this.columnsBarHeight + 'px'
content.appendChild(this.sheet.element); content.appendChild(this.sheet.element);
content.classList.add(CSS_PREFIX + "content"); content.classList.add(CSS_PREFIX + "content");
this.table.element.appendChild(this.toolbar.element); this.table.element.appendChild(this.toolbar.element);
this.table.element.appendChild(this.columnsBar.element)
this.table.element.appendChild(content); this.table.element.appendChild(content);
this.table.element.appendChild(this.scroller.element); this.table.element.appendChild(this.scroller.element);
this.table.element.append(this.editor.element); this.table.element.append(this.editor.element);
@ -171,6 +174,10 @@ export default class Spreadsheet {
return this.config.view; return this.config.view;
} }
get columnsBarHeight() {
return this.columnsBar.height
}
/** Focusing on interactive part of spreadsheet */ /** Focusing on interactive part of spreadsheet */
focusTable() { focusTable() {
this.scroller.element.focus(); this.scroller.element.focus();
@ -246,6 +253,10 @@ export default class Spreadsheet {
this.sheet.renderSheet(); this.sheet.renderSheet();
} }
renderColumnsBar() {
this.columnsBar.renderBar()
}
renderCell(row: number, col: number) { renderCell(row: number, col: number) {
this.data[row][col].render(this); this.data[row][col].render(this);
} }

View File

@ -2,8 +2,6 @@ $css_prefix: "modern_sc_";
.#{$css_prefix}content { .#{$css_prefix}content {
position: absolute; position: absolute;
top: 0;
left: 0;
} }
.#{$css_prefix}spreadsheet_container { .#{$css_prefix}spreadsheet_container {
@ -18,6 +16,7 @@ $css_prefix: "modern_sc_";
} }
.#{$css_prefix}scroller { .#{$css_prefix}scroller {
position: absolute;
overflow: scroll; overflow: scroll;
box-sizing: border-box; box-sizing: border-box;
transform: translateZ(0); transform: translateZ(0);