import { BaseDrawService } from '../../../core/draw/baseDraw'; import type { LetterTracingData, TripleSection, SingleLineRow, } from '../generators/letter-tracing-generator'; import { fontFamilyOf, PRINT_CLEARLY_DASHED, } from '../../shared/data/fontProfiles'; import { calcLetterFontSizes, drawFourLineGrid, drawLetterInFourLineGrid, FOUR_LINE_GRID_H, loadLetterFont, type LetterFontSizes, } from '../../shared/draw/drawTools'; // 每行可容纳的格子数(用于三字母精练模板,一行展示 6 个位置) const SLOTS_PER_ROW = 6; // 大小写字母配对间的间隔(px,字母间距) const PAIR_GAP = 25; // 同一字母区域内相邻两行四线三格之间的间距(px) const TRIPLE_ROW_GAP = 10; // 相邻两个字母区域之间的间距(px),大于 TRIPLE_ROW_GAP const TRIPLE_SECTION_GAP = 20; type TripleData = Extract; /** * 三字母精练绘制: * 3 个字母区域,每区域 4 行四线三格。 * 前两行展示完整颜色递进(黑→浅红→半透明浅红→虚线), * 后两行只展示黑色+浅红色两组,其余空白供用户书写。 * 区域之间间距大于行间距。 */ export default class TripleDraw extends BaseDrawService { private letterSizes: LetterFontSizes = calcLetterFontSizes(FOUR_LINE_GRID_H); private dashedSizes: LetterFontSizes = calcLetterFontSizes( FOUR_LINE_GRID_H, PRINT_CLEARLY_DASHED, ); async draw(data: TripleData) { this.prepareDraw(); await Promise.all([ this.drawHeaderAndDivider(), loadLetterFont(PRINT_CLEARLY_DASHED), ]); this.drawContent(data.sections); this.drawPrintFooter(); } private drawContent(sections: TripleSection[]) { const M = 24; const lineW = this.canvasWidth - M * 2; const slotW = lineW / SLOTS_PER_ROW; let y = this.currentY + 10; for (let s = 0; s < sections.length; s++) { const section = sections[s]; for (let r = 0; r < section.rows.length; r++) { drawFourLineGrid(this.ctx, M, y, lineW, FOUR_LINE_GRID_H); this.drawRow(section.rows[r], M, y, slotW); y += FOUR_LINE_GRID_H; if (r < section.rows.length - 1) { y += TRIPLE_ROW_GAP; } } if (s < sections.length - 1) { y += TRIPLE_SECTION_GAP; } } } private drawRow( row: SingleLineRow, marginX: number, y: number, slotW: number, ) { for (let j = 0; j < row.cells.length; j++) { const cell = row.cells[j]; if (!cell) continue; const pairCx = marginX + j * slotW + slotW / 2; const isDashed = cell.style === 'dashed'; const sizes = isDashed ? this.dashedSizes : this.letterSizes; const fontFamily = fontFamilyOf( isDashed ? PRINT_CLEARLY_DASHED : sizes._profile, ); this.ctx.save(); this.ctx.globalAlpha = cell.alpha; drawLetterInFourLineGrid( this.ctx, cell.upper, pairCx - PAIR_GAP / 2, y, FOUR_LINE_GRID_H, sizes, { fontFamily, color: cell.color }, ); drawLetterInFourLineGrid( this.ctx, cell.lower, pairCx + PAIR_GAP / 2, y, FOUR_LINE_GRID_H, sizes, { fontFamily, color: cell.color }, ); this.ctx.restore(); } } }