132 lines
3.8 KiB
TypeScript
132 lines
3.8 KiB
TypeScript
import { BaseDrawService } from '../../../core/draw/baseDraw';
|
|
import type { LetterTracingData } from '../generators/letter-tracing-generator';
|
|
import {
|
|
PRINT_CLEARLY_BOLD,
|
|
PRINT_CLEARLY_DASHED,
|
|
fontFamilyOf,
|
|
} from '../../../core/font/fontProfiles';
|
|
import {
|
|
calcLetterFontSizes,
|
|
drawFourLineGrid,
|
|
drawLetterInFourLineGrid,
|
|
FOUR_LINE_GRID_H,
|
|
loadLetterFont,
|
|
type LetterFontSizes,
|
|
} from '../../shared/draw/drawTools';
|
|
import { TRACING_COLORS } from '../../../core/data/tracingStyles';
|
|
|
|
type UpperLowerData = Extract<
|
|
LetterTracingData,
|
|
{ mode: 'letter-tracing-upper-lower' }
|
|
>;
|
|
|
|
const M = 24;
|
|
const SECTION_GAP = 25;
|
|
const TITLE_SIZE = 28;
|
|
const TITLE_GAP = 25;
|
|
const ROW_GAP = 24;
|
|
const TITLE_COLOR = '#000';
|
|
|
|
const TRACE_LIGHT_RED = TRACING_COLORS.guide;
|
|
|
|
const DASHED_PROFILE = PRINT_CLEARLY_DASHED;
|
|
const TITLE_PROFILE = PRINT_CLEARLY_BOLD;
|
|
const LETTER_FACE = fontFamilyOf(DASHED_PROFILE);
|
|
const TITLE_FACE = fontFamilyOf(TITLE_PROFILE);
|
|
|
|
/**
|
|
* 字母总览:上区大写、下区小写;每区标题 + 4 行四线三格(7+7+6+6)。
|
|
* 列宽按 7 列均分;后两行 6 字左对齐,与前两行逐列对齐(占前 6 列)。
|
|
*/
|
|
export default class UpperLowerDraw extends BaseDrawService {
|
|
private letterSizes: LetterFontSizes = calcLetterFontSizes(
|
|
FOUR_LINE_GRID_H,
|
|
DASHED_PROFILE,
|
|
);
|
|
|
|
async draw(data: UpperLowerData) {
|
|
this.prepareDraw();
|
|
await Promise.allSettled([
|
|
loadLetterFont(DASHED_PROFILE),
|
|
loadLetterFont(TITLE_PROFILE),
|
|
]);
|
|
await this.drawHeaderAndDivider();
|
|
this.drawUpperLowerBody(data.upperRows, data.lowerRows);
|
|
await this.drawPrintFooter();
|
|
}
|
|
|
|
private drawUpperLowerBody(
|
|
upperRows: string[][],
|
|
lowerRows: string[][],
|
|
): void {
|
|
const lineW = this.canvasWidth - M * 2;
|
|
const slotW = lineW / 7;
|
|
|
|
let y = this.currentY + SECTION_GAP - 7;
|
|
|
|
y = this.drawLetterBlock(
|
|
'Uppercase Letters',
|
|
upperRows,
|
|
y,
|
|
lineW,
|
|
slotW,
|
|
);
|
|
y += SECTION_GAP + 7;
|
|
this.drawLetterBlock('lowercase letters', lowerRows, y, lineW, slotW);
|
|
}
|
|
|
|
/**
|
|
* 绘制一个分区:居中标题 + 4 行四线三格与字母。
|
|
* @returns 该分区最后一行四线三格底边 Y
|
|
*/
|
|
private drawLetterBlock(
|
|
title: string,
|
|
rows: string[][],
|
|
startY: number,
|
|
lineW: number,
|
|
slotW: number,
|
|
): number {
|
|
const ctx = this.ctx;
|
|
const centerX = M + lineW / 2;
|
|
|
|
ctx.save();
|
|
ctx.font = `bold ${TITLE_SIZE}px ${TITLE_FACE}`;
|
|
ctx.fillStyle = TITLE_COLOR;
|
|
ctx.textAlign = 'center';
|
|
ctx.textBaseline = 'top';
|
|
ctx.fillText(title, centerX, startY);
|
|
ctx.restore();
|
|
|
|
let y = startY + TITLE_SIZE + TITLE_GAP;
|
|
|
|
for (let r = 0; r < rows.length; r++) {
|
|
const chars = rows[r];
|
|
drawFourLineGrid(ctx, M, y, lineW, FOUR_LINE_GRID_H);
|
|
|
|
/** 与 7 字行共用列宽 slotW,后两行 6 字左对齐(占前 6 列),与上行逐列对齐 */
|
|
const offsetX = M;
|
|
for (let i = 0; i < chars.length; i++) {
|
|
const cx = offsetX + slotW * (i + 0.5);
|
|
drawLetterInFourLineGrid(
|
|
ctx,
|
|
chars[i],
|
|
cx,
|
|
y,
|
|
FOUR_LINE_GRID_H,
|
|
this.letterSizes,
|
|
{
|
|
fontFamily: LETTER_FACE,
|
|
color: TRACE_LIGHT_RED,
|
|
},
|
|
);
|
|
}
|
|
y += FOUR_LINE_GRID_H;
|
|
if (r < rows.length - 1) {
|
|
y += ROW_GAP;
|
|
}
|
|
}
|
|
|
|
return y;
|
|
}
|
|
}
|