export const fillTextCentered = ( ctx: CanvasRenderingContext2D, text: string, x: number, y: number, width: number, ): number => { const measure = ctx.measureText(text); const textX = Math.floor(x + width / 2 - measure.actualBoundingBoxRight / 2); const textY = measure.actualBoundingBoxAscent + measure.actualBoundingBoxDescent; ctx.fillText(text, textX, y + textY); return measure.actualBoundingBoxAscent + measure.actualBoundingBoxDescent + 1; }; export const fillTextHCentered = ( ctx: CanvasRenderingContext2D, text: string, x: number, y: number, width: number, ) => { const measure = ctx.measureText(text); const textX = Math.floor(x + width / 2 - measure.actualBoundingBoxRight / 2); ctx.fillText(text, textX, y); }; export const fillTextWordWrapped = ( ctx: CanvasRenderingContext2D, text: string, x: number, y: number, width: number, lineHeight?: number, ): number => { const words = text.split(" "); let line = ""; let currentY = y; let lineCount = 0; const height = lineHeight || ctx.measureText("M").actualBoundingBoxAscent + ctx.measureText("M").actualBoundingBoxDescent; currentY += height; for (let i = 0; i < words.length; i++) { const testLine = line + (line ? " " : "") + words[i]; const metrics = ctx.measureText(testLine); const testWidth = metrics.width; if (testWidth > width && line) { ctx.fillText(line, x, currentY); line = words[i]!; currentY += height; lineCount++; } else { line = testLine; } } if (line) { ctx.fillText(line, x, currentY); lineCount++; } return lineCount * height; };