fix: enhance fitCanvasText function with caching and improve text fitting logic

This commit is contained in:
t8y2 2026-06-04 21:32:59 +08:00
parent 5e21b74487
commit 25188bc5c5
1 changed files with 27 additions and 4 deletions

View File

@ -92,10 +92,30 @@ function canvasTabularFontFamily(fontFamily: string): string {
return `"Geist Variable Tabular", ${fontFamily}`;
}
const FIT_CANVAS_TEXT_CACHE_MAX = 10000;
const fitCanvasTextCache = new Map<string, string>();
export function clearFitCanvasTextCache(): void {
fitCanvasTextCache.clear();
}
function fitCanvasText(ctx: CanvasRenderingContext2D, text: string, maxWidth: number): string {
if (maxWidth <= 0 || ctx.measureText(text).width <= maxWidth) return text;
if (maxWidth <= 0) return "";
const font = ctx.font;
const cacheKey = `${font}|${text}|${maxWidth}`;
const cached = fitCanvasTextCache.get(cacheKey);
if (cached !== undefined) return cached;
if (ctx.measureText(text).width <= maxWidth) {
if (fitCanvasTextCache.size >= FIT_CANVAS_TEXT_CACHE_MAX) fitCanvasTextCache.clear();
fitCanvasTextCache.set(cacheKey, text);
return text;
}
const ellipsis = "...";
if (ctx.measureText(ellipsis).width > maxWidth) return "";
if (ctx.measureText(ellipsis).width > maxWidth) {
if (fitCanvasTextCache.size >= FIT_CANVAS_TEXT_CACHE_MAX) fitCanvasTextCache.clear();
fitCanvasTextCache.set(cacheKey, "");
return "";
}
let low = 0;
let high = text.length;
while (low < high) {
@ -103,7 +123,10 @@ function fitCanvasText(ctx: CanvasRenderingContext2D, text: string, maxWidth: nu
if (ctx.measureText(`${text.slice(0, mid)}${ellipsis}`).width <= maxWidth) low = mid;
else high = mid - 1;
}
return `${text.slice(0, low)}${ellipsis}`;
const result = `${text.slice(0, low)}${ellipsis}`;
if (fitCanvasTextCache.size >= FIT_CANVAS_TEXT_CACHE_MAX) fitCanvasTextCache.clear();
fitCanvasTextCache.set(cacheKey, result);
return result;
}
function canvasFont(style: {
@ -390,7 +413,7 @@ export function drawCanvasDataGrid(options: DrawCanvasDataGridOptions) {
const textMaxWidth = Math.max(0, x + colWidth - textLeft - 12);
const isEditingThisCell = editingCell?.rowId === item.id && editingCell.col === actualColIdx;
const displayText = isEditingThisCell ? "" : formatCell(value, actualColIdx);
const text = isEditingThisCell || isScrolling ? displayText : fitCanvasText(ctx, displayText, textMaxWidth);
const text = isEditingThisCell ? displayText : fitCanvasText(ctx, displayText, textMaxWidth);
ctx.fillText(text, textLeft, y + CANVAS_DATA_GRID_ROW_HEIGHT / 2);
if (item.isDeleted && text) {
const textWidth = Math.min(ctx.measureText(text).width, textMaxWidth);