diff options
Diffstat (limited to 'web')
| -rw-r--r-- | web/src/components/grid/index.ts | 5 | ||||
| -rw-r--r-- | web/src/index.ts | 80 | ||||
| -rw-r--r-- | web/src/math/Ratio.ts | 7 |
3 files changed, 87 insertions, 5 deletions
diff --git a/web/src/components/grid/index.ts b/web/src/components/grid/index.ts index 5301afb..15f26a9 100644 --- a/web/src/components/grid/index.ts +++ b/web/src/components/grid/index.ts @@ -28,6 +28,11 @@ class NotiveGridElement extends HTMLElement { } window.addEventListener("ntv:selectionchange", () => this.draw()); + window.addEventListener("ntv:grid:change", (event) => { + if (event.detail.gridId === this.gridId) { + this.draw(); + } + }); this.canvasEl.addEventListener( "mousedown", diff --git a/web/src/index.ts b/web/src/index.ts index f923c56..35af24c 100644 --- a/web/src/index.ts +++ b/web/src/index.ts @@ -1,7 +1,10 @@ import Ratio from "./math/Ratio"; import { Cell, CellRef, Doc, Grid, mapRowsInRange } from "./types"; import { ActiveCellSelection, Selection } from "./selection"; -import renderGrid, { RenderedGrid } from "./components/grid/renderGrid"; +import renderGrid, { + getRenderedCell, + RenderedGrid, +} from "./components/grid/renderGrid"; function defaultDoc(): Doc { const defaultCells: Cell[] = Array.from({ length: 16 }, () => ({ @@ -101,18 +104,85 @@ export default class Notive { subdivideSelection(subdivisions: number) { const selection = this.selection; - if (!selection) return; + const grid = this.getGrid(selection.gridId); + if (!grid) return; + + const startCellRef = selection.startCellRef(); + const endCellRef = selection.endCellRef(); + + const startCell = getRenderedCell(grid, startCellRef); + const endCell = getRenderedCell(grid, endCellRef); + if (!startCell || !endCell) return; + + const startRatio = + startCell.startRatio.compare(endCell.startRatio) <= 0 + ? startCell.startRatio + : endCell.startRatio; + + const endRatio = + startCell.endRatio.compare(endCell.endRatio) >= 0 + ? startCell.endRatio + : endCell.endRatio; + + const totalWidth = endRatio.subtract(startRatio); + const subdivisionWidth = totalWidth.divideRatio( + Ratio.fromInteger(subdivisions), + ); + const newDoc = mapRowsInRange( this.doc, selection.gridId, - selection.startCellRef(), - selection.endCellRef(), + startCellRef, + endCellRef, (row, rowRef) => { - return row; + const newCells: Cell[] = []; + let currentRatio = Ratio.fromInteger(0); + + for (const cell of row.cells) { + const cellStart = currentRatio; + const cellEnd = currentRatio.add(cell.widthRatio); + + // Cell is entirely before selection + if (cellEnd.compare(startRatio) <= 0) { + newCells.push(cell); + currentRatio = cellEnd; + continue; + } + + // Cell is entirely after selection + if (cellStart.compare(endRatio) >= 0) { + newCells.push(cell); + currentRatio = cellEnd; + continue; + } + + // First cell that overlaps - insert subdivisions + if (newCells.length === 0 || currentRatio.compare(startRatio) < 0) { + for (let i = 0; i < subdivisions; i++) { + newCells.push({ widthRatio: subdivisionWidth }); + } + } + + currentRatio = cellEnd; + } + + return { ...row, cells: newCells }; }, ); + + this.#doc = newDoc; + + this.#gridsById = Object.fromEntries( + this.#doc.grids.map((grid) => [grid.id, renderGrid(grid)]), + ); + + window.dispatchEvent( + new CustomEvent("ntv:grid:change", { + detail: { gridId: selection.gridId }, + }), + ); } } diff --git a/web/src/math/Ratio.ts b/web/src/math/Ratio.ts index d8e1149..0cca966 100644 --- a/web/src/math/Ratio.ts +++ b/web/src/math/Ratio.ts @@ -50,6 +50,13 @@ export default class Ratio { ); } + subtract(other: Ratio): Ratio { + return new Ratio( + this.numerator * other.denominator - other.numerator * this.denominator, + this.denominator * other.denominator, + ); + } + compare(other: Ratio): number { const left = this.numerator * other.denominator; const right = other.numerator * this.denominator; |
