diff options
| author | Josh Kingsley <josh@joshkingsley.me> | 2025-10-26 21:50:23 +0200 |
|---|---|---|
| committer | Josh Kingsley <josh@joshkingsley.me> | 2025-10-26 21:50:23 +0200 |
| commit | ed566a3f657e8256df9aabd107c199e6971a8f96 (patch) | |
| tree | 4cabda5caf337cf787f0049d28dfa6a33a88fa3f /web/src/index.ts | |
| parent | 5e56338bb3e9bb1bcf1ef1c1fe6afb9c7391d976 (diff) | |
feat(web): subdivide cells
Diffstat (limited to 'web/src/index.ts')
| -rw-r--r-- | web/src/index.ts | 80 |
1 files changed, 75 insertions, 5 deletions
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 }, + }), + ); } } |
