diff options
Diffstat (limited to 'web/src/components')
| -rw-r--r-- | web/src/components/app/index.ts | 4 | ||||
| -rw-r--r-- | web/src/components/grid/drawGrid.ts | 30 | ||||
| -rw-r--r-- | web/src/components/grid/index.css | 2 | ||||
| -rw-r--r-- | web/src/components/grid/index.ts | 26 | ||||
| -rw-r--r-- | web/src/components/grid/renderGrid.ts | 127 |
5 files changed, 183 insertions, 6 deletions
diff --git a/web/src/components/app/index.ts b/web/src/components/app/index.ts index 5967a46..2782e22 100644 --- a/web/src/components/app/index.ts +++ b/web/src/components/app/index.ts @@ -4,8 +4,8 @@ import "./index.css"; class NotiveAppElement extends HTMLElement { connectedCallback() { this.append( - ...window.notive.doc.grids.map((_grid) => { - return ntvGrid(); + ...window.notive.doc.grids.map((grid) => { + return ntvGrid({ gridId: grid.id }); }), ); } diff --git a/web/src/components/grid/drawGrid.ts b/web/src/components/grid/drawGrid.ts new file mode 100644 index 0000000..6284693 --- /dev/null +++ b/web/src/components/grid/drawGrid.ts @@ -0,0 +1,30 @@ +import { RenderedGrid } from "./renderGrid"; +import colors from "open-color"; + +export default function drawGrid( + ctx: CanvasRenderingContext2D, + grid: RenderedGrid, +) { + ctx.clearRect(0, 0, grid.rect.width, grid.rect.height); + + ctx.fillStyle = colors.gray[8]; + ctx.fillRect(0, 0, grid.rect.width, grid.rect.height); + + ctx.strokeStyle = colors.gray[7]; + + grid.renderedRows.forEach((row, renderedRowIndex) => { + const isLastRow = renderedRowIndex === grid.renderedRows.length - 1; + + row.renderedCells.forEach((cell, cellIndex) => { + const { topLeft, width, height } = cell.rect; + const isLastCell = cellIndex === row.renderedCells.length - 1; + + ctx.strokeRect( + topLeft.x + 0.5, + topLeft.y + 0.5, + isLastCell ? width - 1 : width, + isLastRow ? height - 1 : height, + ); + }); + }); +} diff --git a/web/src/components/grid/index.css b/web/src/components/grid/index.css index 296c155..0fad720 100644 --- a/web/src/components/grid/index.css +++ b/web/src/components/grid/index.css @@ -1,8 +1,8 @@ ntv-grid { display: block; + padding: 1.5rem; } ntv-grid > canvas { display: block; - width: 100%; } diff --git a/web/src/components/grid/index.ts b/web/src/components/grid/index.ts index 18bf75a..829a511 100644 --- a/web/src/components/grid/index.ts +++ b/web/src/components/grid/index.ts @@ -1,11 +1,27 @@ import h, { type CreateElement } from "../../html"; +import renderGrid from "./renderGrid"; +import drawGrid from "./drawGrid"; import "./index.css"; -import colors from "open-color"; class NotiveGridElement extends HTMLElement { + #gridId!: string; + + get gridId() { + return this.#gridId; + } + + set gridId(val: string) { + this.#gridId = val; + this.setAttribute("grid-id", val); + } + canvasEl: HTMLCanvasElement = h.canvas(); connectedCallback() { + if (!this.gridId) { + throw new Error("ntv-grid requries gridId attribute"); + } + this.append(this.canvasEl); this.draw(); } @@ -13,8 +29,12 @@ class NotiveGridElement extends HTMLElement { draw() { const ctx = this.canvasEl.getContext("2d"); if (!ctx) throw new Error("Unable to get canvas context"); - ctx.fillStyle = colors.gray[8]; - ctx.fillRect(0, 0, this.canvasEl.width, this.canvasEl.height); + const grid = window.notive.getGrid(this.gridId); + if (!grid) return; + const renderedGrid = renderGrid(grid); + this.canvasEl.setAttribute("width", renderedGrid.rect.width + "px"); + this.canvasEl.setAttribute("height", renderedGrid.rect.height + "px"); + drawGrid(ctx, renderedGrid); } } diff --git a/web/src/components/grid/renderGrid.ts b/web/src/components/grid/renderGrid.ts new file mode 100644 index 0000000..5666f66 --- /dev/null +++ b/web/src/components/grid/renderGrid.ts @@ -0,0 +1,127 @@ +import Ratio from "../../math/Ratio"; +import Rect from "../../math/Rect"; +import { Cell, CellRef, Grid, Row, RowRef } from "./types"; + +export interface RenderedCell extends Cell { + cellRef: CellRef; + renderedRowIndex: number; + rect: Rect; +} + +export interface RenderedRow { + rowRef: RowRef; + rect: Rect; + renderedCells: RenderedCell[]; +} + +export interface RenderedGrid extends Grid { + rect: Rect; + renderedRows: RenderedRow[]; +} + +function renderCell( + grid: Grid, + cell: Cell, + cellRef: CellRef, + renderedRowIndex: number, + topLeftX: number, + topLeftY: number, +): RenderedCell { + const width = cell.widthRatio + .divideRatio(grid.baseCellWidthRatio) + .multiplyRatio(Ratio.fromInteger(grid.baseCellSize)) + .toNumber(); + + const rect = new Rect(topLeftX, topLeftY, width, grid.baseCellSize); + + return { ...cell, cellRef, rect, renderedRowIndex }; +} + +function renderRow( + grid: Grid, + row: Row, + rowRef: RowRef, + renderedRowIndex: number, + topLeftY: number, +): RenderedRow { + if (row.cells.length === 0) { + return { + ...row, + rowRef, + rect: new Rect(0, topLeftY, 0, 0), + renderedCells: [], + }; + } + + let topLeftX = 0; + + const renderedCells = row.cells.map((cell, cellIndex) => { + const cellRef = { ...rowRef, cellIndex }; + + const renderedCell = renderCell( + grid, + cell, + cellRef, + renderedRowIndex, + topLeftX, + topLeftY, + ); + + topLeftX = renderedCell.rect.bottomRight.x; + + return renderedCell; + }); + + const { topLeft } = renderedCells[0].rect; + const { bottomRight } = renderedCells.at(-1)!.rect; + + const rect = new Rect( + topLeft.x, + topLeft.y, + bottomRight.x - topLeft.x, + bottomRight.y - topLeft.y, + ); + + return { ...row, renderedCells, rect, rowRef }; +} + +function renderRows(grid: Grid): RenderedRow[] { + const renderedRows: RenderedRow[] = []; + + let partIndex = 0; + let rowIndex = 0; + let topLeftY = 0; + let renderedRowIndex = 0; + + while (true) { + if (!grid.parts[partIndex]?.rows[rowIndex]) break; + + const row = grid.parts[partIndex].rows[rowIndex]; + const rowRef = { partIndex, rowIndex }; + const renderedRow = renderRow( + grid, + row, + rowRef, + renderedRowIndex, + topLeftY, + ); + + topLeftY = renderedRow.rect.bottomRight.y; + renderedRows.push(renderedRow); + + if (!grid.parts[++partIndex]) { + partIndex = 0; + rowIndex++; + } + + renderedRowIndex++; + } + + return renderedRows; +} + +export default function renderGrid(grid: Grid) { + const renderedRows = renderRows(grid); + const rect = renderedRows[0].rect.extend(renderedRows.at(-1)!.rect); + return { ...grid, rect, renderedRows }; +} |
