summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--web/src/components/grid/drawGrid.ts11
-rw-r--r--web/src/components/grid/renderGrid.ts19
-rw-r--r--web/src/components/toolbar/index.ts53
-rw-r--r--web/src/math/Ratio.ts25
-rw-r--r--web/src/selection.ts52
-rw-r--r--web/src/types.ts1
6 files changed, 143 insertions, 18 deletions
diff --git a/web/src/components/grid/drawGrid.ts b/web/src/components/grid/drawGrid.ts
index 5ea17b6..1b94254 100644
--- a/web/src/components/grid/drawGrid.ts
+++ b/web/src/components/grid/drawGrid.ts
@@ -1,6 +1,6 @@
import { RangeSelection, Selection } from "../../selection";
import { CellRef } from "../../types";
-import { RenderedCell, RenderedGrid } from "./renderGrid";
+import { getRenderedCell, RenderedCell, RenderedGrid } from "./renderGrid";
interface GridColors {
bgFill: string;
@@ -74,15 +74,6 @@ function strokeGridLines(
});
}
-function getRenderedCell(
- grid: RenderedGrid,
- cellRef: CellRef,
-): RenderedCell | undefined {
- const rowsPerPart = grid.renderedRows.length / grid.parts.length;
- const renderedRowIndex = cellRef.partIndex * rowsPerPart + cellRef.rowIndex;
- return grid.renderedRows[renderedRowIndex]?.renderedCells[cellRef.cellIndex];
-}
-
function strokeActiveCell(
ctx: CanvasRenderingContext2D,
colors: GridColors,
diff --git a/web/src/components/grid/renderGrid.ts b/web/src/components/grid/renderGrid.ts
index 7ef8813..e6a2c54 100644
--- a/web/src/components/grid/renderGrid.ts
+++ b/web/src/components/grid/renderGrid.ts
@@ -6,6 +6,8 @@ export interface RenderedCell extends Cell {
cellRef: CellRef;
renderedRowIndex: number;
rect: Rect;
+ startRatio: Ratio;
+ endRatio: Ratio;
}
export interface RenderedRow {
@@ -26,6 +28,7 @@ function renderCell(
renderedRowIndex: number,
topLeftX: number,
topLeftY: number,
+ startRatio: Ratio,
): RenderedCell {
const width = cell.widthRatio
.divideRatio(grid.baseCellWidthRatio)
@@ -34,7 +37,9 @@ function renderCell(
const rect = new Rect(topLeftX, topLeftY, width, grid.baseCellSize);
- return { ...cell, cellRef, rect, renderedRowIndex };
+ const endRatio = startRatio.add(cell.widthRatio);
+
+ return { ...cell, cellRef, rect, renderedRowIndex, startRatio, endRatio };
}
function renderRow(
@@ -54,6 +59,7 @@ function renderRow(
}
let topLeftX = 0;
+ let startRatio = Ratio.fromInteger(0);
const renderedCells = row.cells.map((cell, cellIndex) => {
const cellRef = { ...rowRef, cellIndex };
@@ -65,9 +71,11 @@ function renderRow(
renderedRowIndex,
topLeftX,
topLeftY,
+ startRatio,
);
topLeftX = renderedCell.rect.bottomRight.x;
+ startRatio = renderedCell.endRatio;
return renderedCell;
});
@@ -125,3 +133,12 @@ export default function renderGrid(grid: Grid) {
const rect = renderedRows[0].rect.extend(renderedRows.at(-1)!.rect);
return { ...grid, rect, renderedRows };
}
+
+export function getRenderedCell(
+ grid: RenderedGrid,
+ cellRef: CellRef,
+): RenderedCell | undefined {
+ const rowsPerPart = grid.renderedRows.length / grid.parts.length;
+ const renderedRowIndex = cellRef.partIndex * rowsPerPart + cellRef.rowIndex;
+ return grid.renderedRows[renderedRowIndex]?.renderedCells[cellRef.cellIndex];
+}
diff --git a/web/src/components/toolbar/index.ts b/web/src/components/toolbar/index.ts
index d844a69..e672a48 100644
--- a/web/src/components/toolbar/index.ts
+++ b/web/src/components/toolbar/index.ts
@@ -1,8 +1,59 @@
import h, { CreateElement } from "../../html";
+import { ActiveCellSelection, RangeSelection } from "../../selection";
+import { RenderedGrid } from "../grid/renderGrid";
import "./index.css";
+function getSelectedSubdivisionsCount(): number | undefined {
+ const selection = window.notive.selection;
+
+ if (!selection) return;
+
+ if (selection instanceof ActiveCellSelection) {
+ return 1;
+ }
+
+ if (!(selection instanceof RangeSelection)) return;
+
+ const grid = window.notive.getGrid(selection.gridId);
+
+ if (!grid) return;
+
+ const selectedCells = selection.getSelectedCells(grid);
+
+ return Math.min(...selectedCells.map((cells) => cells.length));
+}
+
class NotiveToolbarElement extends HTMLElement {
+ #subdivisionsInputEl: HTMLInputElement = h.input({
+ title: "Subdivisions",
+ placeholder: "-",
+ disabled: true,
+ });
+
connectedCallback() {
+ this.#render();
+
+ window.addEventListener("ntv:selection-changed", () => {
+ if (window.notive.pendingSelection) {
+ this.#subdivisionsInputEl.disabled = true;
+ this.#subdivisionsInputEl.value = "";
+ return;
+ }
+
+ const subdivisionsCount = getSelectedSubdivisionsCount();
+
+ if (!subdivisionsCount) {
+ this.#subdivisionsInputEl.disabled = true;
+ this.#subdivisionsInputEl.value = "";
+ return;
+ }
+
+ this.#subdivisionsInputEl.disabled = false;
+ this.#subdivisionsInputEl.value = subdivisionsCount.toString();
+ });
+ }
+
+ #render() {
this.append(
h.section(
h.button({ dataset: { variant: "menu" } }, "File"),
@@ -11,7 +62,7 @@ class NotiveToolbarElement extends HTMLElement {
),
h.section(
h.button({ dataset: { variant: "icon" } }, "-"),
- h.input({ type: "text", value: "1" }),
+ this.#subdivisionsInputEl,
h.button({ dataset: { variant: "icon" } }, "+"),
),
);
diff --git a/web/src/math/Ratio.ts b/web/src/math/Ratio.ts
index 4973ff4..d8e1149 100644
--- a/web/src/math/Ratio.ts
+++ b/web/src/math/Ratio.ts
@@ -3,15 +3,15 @@ export type RatioData = [numerator: number, denominator: number];
/** Representation of a ratio for performing fractional artithmetic. */
export default class Ratio {
- private readonly _numerator: number;
- private readonly _denominator: number;
+ readonly #numerator: number;
+ readonly #denominator: number;
get numerator(): number {
- return this._numerator;
+ return this.#numerator;
}
get denominator(): number {
- return this._denominator;
+ return this.#denominator;
}
constructor(numerator: number, denominator: number) {
@@ -25,8 +25,8 @@ export default class Ratio {
throw new RangeError("Ratio demnominator cannot be zero");
}
- this._numerator = numerator;
- this._denominator = denominator;
+ this.#numerator = numerator;
+ this.#denominator = denominator;
}
multiplyRatio(other: Ratio): Ratio {
@@ -43,6 +43,19 @@ export default class Ratio {
);
}
+ add(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;
+ return left < right ? -1 : left > right ? 1 : 0;
+ }
+
toNumber(): number {
return this.numerator / this.denominator;
}
diff --git a/web/src/selection.ts b/web/src/selection.ts
index 3d18417..294db52 100644
--- a/web/src/selection.ts
+++ b/web/src/selection.ts
@@ -1,3 +1,8 @@
+import {
+ getRenderedCell,
+ RenderedCell,
+ RenderedGrid,
+} from "./components/grid/renderGrid";
import { CellRef, cellRefEquals } from "./types";
export abstract class Selection {
@@ -10,6 +15,8 @@ export abstract class Selection {
}
abstract extend(cellRef: CellRef): Selection;
+
+ abstract getSelectedCells(grid: RenderedGrid): RenderedCell[][];
}
export class ActiveCellSelection extends Selection {
@@ -23,6 +30,10 @@ export class ActiveCellSelection extends Selection {
cellRef,
]);
}
+
+ getSelectedCells(grid: RenderedGrid): RenderedCell[][] {
+ return [[getRenderedCell(grid, this.activeCellRef)!]];
+ }
}
export type CellRange = [CellRef, CellRef];
@@ -49,4 +60,45 @@ export class RangeSelection extends Selection {
cellRef,
]);
}
+
+ getSelectedCells(grid: RenderedGrid): RenderedCell[][] {
+ const startCell = getRenderedCell(grid, this.range[0]);
+ const endCell = getRenderedCell(grid, this.range[1]);
+
+ if (!startCell || !endCell) return [];
+
+ const firstRowIndex = Math.min(
+ startCell.renderedRowIndex,
+ endCell.renderedRowIndex,
+ );
+
+ const lastRowIndex = Math.max(
+ startCell.renderedRowIndex,
+ endCell.renderedRowIndex,
+ );
+
+ const startRatio =
+ startCell.startRatio.compare(endCell.startRatio) <= 0
+ ? startCell.startRatio
+ : endCell.startRatio;
+
+ const endRatio =
+ startCell.endRatio.compare(endCell.endRatio) >= 0
+ ? startCell.endRatio
+ : endCell.endRatio;
+
+ return grid.renderedRows
+ .slice(firstRowIndex, lastRowIndex + 1)
+ .map((row) => {
+ const firstCellIndex = row.renderedCells.findIndex(
+ (cell) => cell.startRatio.compare(startRatio) >= 0,
+ );
+
+ const lastCellIndex = row.renderedCells.findLastIndex(
+ (cell) => cell.endRatio.compare(endRatio) <= 0,
+ );
+
+ return row.renderedCells.slice(firstCellIndex, lastCellIndex + 1);
+ });
+ }
}
diff --git a/web/src/types.ts b/web/src/types.ts
index 9b7a51a..d932389 100644
--- a/web/src/types.ts
+++ b/web/src/types.ts
@@ -30,6 +30,7 @@ export interface RowRef {
rowIndex: number;
}
+// TODO Should probably have a gridId
export interface CellRef {
partIndex: number;
rowIndex: number;