feat: 开发英语启蒙的入口页
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
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<LetterTracingData, { mode: 'letter-tracing-three' }>;
|
||||
|
||||
/**
|
||||
* 三字母精练绘制:
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user