UNPKG

@pmndrs/uikit

Version:

Build performant 3D user interfaces with Three.js and yoga.

77 lines (76 loc) 3.4 kB
import { getGlyphLayoutHeight, getGlyphOffsetX, getGlyphOffsetY, getKerningOffset, getOffsetToNextGlyph, getOffsetToNextLine, } from '../utils.js'; import { buildGlyphLayout } from './measure.js'; export function buildPositionedGlyphLayout(properties, availableWidth, availableHeight, textAlign, verticalAlign) { const layout = buildGlyphLayout(properties, availableWidth, availableHeight); const positionedLines = []; const { font, fontSize, letterSpacing = 0, lineHeight = 1.2, text } = layout; const whitespaceWidth = getWhitespaceWidth(layout); let y = getTextYOffset(layout, verticalAlign) - availableHeight / 2; for (let lineIndex = 0; lineIndex < layout.lines.length; lineIndex++) { const line = layout.lines[lineIndex]; const entries = []; let offsetPerWhitespace = textAlign === 'justify' && line.whitespacesBetween > 0 ? (availableWidth - line.nonWhitespaceWidth) / line.whitespacesBetween : 0; let x = getTextXOffset(availableWidth, line.nonWhitespaceWidth, textAlign) - availableWidth / 2; let prevGlyphId; for (let charIndex = line.charIndexOffset; charIndex < line.charIndexOffset + line.charLength; charIndex++) { const char = text[charIndex]; const glyphInfo = font.getGlyphInfo(char); x += getKerningOffset(font, fontSize, prevGlyphId, glyphInfo); prevGlyphId = glyphInfo.id; if (char === ' ' || charIndex > line.nonWhitespaceCharLength + line.charIndexOffset) { entries.push({ type: 'whitespace', charIndex, x: x + getGlyphOffsetX(glyphInfo, fontSize), width: whitespaceWidth, }); x += offsetPerWhitespace + getOffsetToNextGlyph(fontSize, glyphInfo, letterSpacing); continue; } entries.push({ type: 'glyph', charIndex, char, glyphInfo, x: x + getGlyphOffsetX(glyphInfo, fontSize), y: -(y + getGlyphOffsetY(fontSize, lineHeight, glyphInfo)), width: glyphInfo.width * fontSize, }); x += getOffsetToNextGlyph(fontSize, glyphInfo, letterSpacing); } positionedLines.push({ ...line, entries }); y += getOffsetToNextLine(lineHeight); } return { ...layout, lines: positionedLines, textAlign, verticalAlign, }; } export function getTextXOffset(availableWidth, nonWhitespaceWidth, textAlign) { switch (textAlign) { case 'right': return availableWidth - nonWhitespaceWidth; case 'center': return (availableWidth - nonWhitespaceWidth) / 2; default: return 0; } } export function getTextYOffset(layout, verticalAlign) { switch (verticalAlign) { case 'center': case 'middle': return (layout.availableHeight - getGlyphLayoutHeight(layout.lines.length, layout.lineHeight)) / 2; case 'bottom': return layout.availableHeight - getGlyphLayoutHeight(layout.lines.length, layout.lineHeight); default: return 0; } } export function getWhitespaceWidth({ font, fontSize }) { return font.getGlyphInfo(' ').xadvance * fontSize; }