UNPKG

wesleytabaka-rpi-led-matrix

Version:

Fork of alexeden/rpi-led-matrix. Node.js/Typescript bindings for hzeller/rpi-rgb-led-matrix

123 lines (101 loc) 3.04 kB
import { FontInstance } from './types'; export interface Glyph { h: number; w: number; char: string; } export interface MappedGlyph extends Glyph { x: number; y: number; } export type Word = Glyph[]; export type Line = Word[]; const isSeparator = ({ char }: Glyph) => char === ' '; const glphysToWords = (glphys: Glyph[]): Word[] => { const index = glphys .map((g, i) => i === 0 && isSeparator(g) ? null : g.char) .indexOf(' '); return index > 0 ? [glphys.slice(0, index), ...glphysToWords(glphys.slice(index))] : [glphys]; }; const calcWordWidth = (gs: Glyph[]) => gs.reduce((sum, { w }) => sum + w, 0); const wordsToLines = (maxWidth: number, words: Word[]): Line[] => { const lines: Line[] = []; let tmpLine: Line = []; let tmpLineWidth = 0; words.filter(({ length }) => length > 0).forEach(word => { const wordWidth = calcWordWidth(word); if (tmpLineWidth + wordWidth > maxWidth) { lines.push(tmpLine); const firstWord = word.filter(g => !isSeparator(g)); tmpLine = [ firstWord ]; tmpLineWidth = calcWordWidth(firstWord); } else { tmpLine.push(word); tmpLineWidth += wordWidth; } }); if (tmpLine.length > 0) lines.push(tmpLine); return lines; }; export enum HorizontalAlignment { Left = 'left', Center = 'center', Right = 'right', } export enum VerticalAlignment { Bottom = 'bottom', Middle = 'middle', Top = 'top', } export class LayoutUtils { static textToLines(font: FontInstance, maxW: number, text: string): Line[] { const fontHeight = font.height(); const glphys = text.split('').map(char => ({ char, h: fontHeight, w: font.stringWidth(char), })); return wordsToLines(maxW, glphysToWords(glphys)); } static linesToMappedGlyphs( lines: Line[], lineH: number, containerW: number, containerH: number, alignH = HorizontalAlignment.Center, alignV = VerticalAlignment.Middle ): MappedGlyph[] { const blockH = lineH * lines.length; const offsetY = (() => { switch (alignV) { case VerticalAlignment.Top: return 0; case VerticalAlignment.Middle: return Math.floor((containerH - blockH) / 2); case VerticalAlignment.Bottom: return containerH - blockH; } })(); return lines.map((words, i) => { const lineGlyphs = words.reduce((glyphs, word) => [...glyphs, ...word], []); const lineW = calcWordWidth(lineGlyphs); let offsetX = (() => { switch (alignH) { case HorizontalAlignment.Left: return 0; case HorizontalAlignment.Center: return Math.floor((containerW - lineW) / 2); case HorizontalAlignment.Right: return containerW - lineW; } })(); return lineGlyphs.map(glyph => { const mapped = { ...glyph, x: offsetX, y: offsetY + i * lineH, }; offsetX += glyph.w; return mapped; }); }) .reduce((glyphs, words) => [...glyphs, ...words], []); } }