summaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
authorJosh Kingsley <josh@joshkingsley.me>2025-10-26 21:50:23 +0200
committerJosh Kingsley <josh@joshkingsley.me>2025-10-26 21:50:23 +0200
commited566a3f657e8256df9aabd107c199e6971a8f96 (patch)
tree4cabda5caf337cf787f0049d28dfa6a33a88fa3f /web
parent5e56338bb3e9bb1bcf1ef1c1fe6afb9c7391d976 (diff)
feat(web): subdivide cells
Diffstat (limited to 'web')
-rw-r--r--web/src/components/grid/index.ts5
-rw-r--r--web/src/index.ts80
-rw-r--r--web/src/math/Ratio.ts7
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;