/
kan64
/
spreadsheet-lab
Обзор
Документация
Войти
/
kan64
/
spreadsheet-lab
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
develop
client/src/utils/cellContentMeasurement.ts
108 строк
3 KB
Anton Kravchenkov
feat(ui): Add rich text cells
23 мар 2026, 23:33
23 мар 2026, 23:33
7b25f1e
Код
Авторство
О чём код?
import Konva from 'konva'; import type { TextRun, CellData, SheetData, CellRange } from '../types/types'; import { cellId, normalizeRange } from './cellUtils'; const FONT_FAMILY = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif"; let _konvaText: Konva.Text | null = null; function getKonvaText(): Konva.Text { if (!_konvaText) _konvaText = new Konva.Text({ text: '' }); return _konvaText; } function measureKonvaHeight(text: string, fontSize: number, width: number, wrap: boolean): number { const t = getKonvaText(); t.text(text); t.fontSize(fontSize); t.fontFamily(FONT_FAMILY); t.lineHeight(1.25); if (wrap && width > 0) { t.width(width); t.wrap('word'); } else { t.width(undefined as unknown as number); t.wrap('none'); } return t.height(); } function measureKonvaTextWidth(text: string, fontSize: number): number { const t = getKonvaText(); t.text(text); t.fontSize(fontSize); t.fontFamily(FONT_FAMILY); t.width(undefined as unknown as number); t.wrap('none'); return t.width(); } function runsToPlainText(runs: TextRun[]): string { return runs.map(r => r.text).join(''); } const PADDING = 8; const LINE_HEIGHT_MULT = 1.25; export function computeContentHeight( cell: CellData | undefined | null, maxWidth: number, wrapText: boolean, fontSize: number ): number { if (!cell) return 0; const text = (cell.richText && cell.richText.length > 0) ? runsToPlainText(cell.richText) : (cell.value ?? ''); if (!text) return 0; const height = measureKonvaHeight(text, fontSize, wrapText ? maxWidth : 0, wrapText); return Math.ceil(height + PADDING); } export function computeRowHeightForContent( sheet: SheetData, row: number, getColWidth: (col: number) => number, mergedCells: CellRange[] | undefined, minHeight: number, maxCols: number = 100 ): number { const mergeMap = new Map<string, { isOrigin: boolean; range: CellRange }>(); for (const m of mergedCells ?? []) { const nm = normalizeRange(m); for (let r = nm.start.row; r <= nm.end.row; r++) { for (let c = nm.start.col; c <= nm.end.col; c++) { const id = cellId(r, c); mergeMap.set(id, { isOrigin: r === nm.start.row && c === nm.start.col, range: nm }); } } } let maxH = minHeight; for (let c = 0; c < maxCols; c++) { const cid = cellId(row, c); const mergeInfo = mergeMap.get(cid); if (mergeInfo && !mergeInfo.isOrigin) continue; let cell: CellData | undefined; let totalWidth = 0; if (mergeInfo?.isOrigin) { const { range } = mergeInfo; for (let cc = range.start.col; cc <= range.end.col; cc++) { totalWidth += getColWidth(cc); } cell = sheet.cells?.[cellId(range.start.row, range.start.col)]; } else { totalWidth = getColWidth(c); cell = sheet.cells?.[cid]; } if (!cell || (!cell.value && (!cell.richText || cell.richText.length === 0))) continue; const wrap = cell.style?.wrapText ?? false; const fs = cell.style?.fontSize ?? 13; const h = computeContentHeight(cell, Math.max(0, totalWidth - 8), wrap, fs); if (h > maxH) maxH = h; } return Math.max(minHeight, maxH); }