113 lines
3.3 KiB
TypeScript
113 lines
3.3 KiB
TypeScript
import { BaseDrawService } from '../../../core/draw/baseDraw';
|
|
import type {
|
|
LetterTracingData,
|
|
SingleLineRow,
|
|
} from '../generators/letter-tracing-generator';
|
|
import {
|
|
fontFamilyOf,
|
|
PRINT_CLEARLY_DASHED,
|
|
} from '../../../core/font/fontProfiles';
|
|
import {
|
|
calcLetterFontSizes,
|
|
drawFourLineGrid,
|
|
drawLetterInFourLineGrid,
|
|
FOUR_LINE_GRID_H,
|
|
loadLetterFont,
|
|
type LetterFontSizes,
|
|
} from '../../shared/draw/drawTools';
|
|
|
|
const SLOTS_PER_ROW = 7;
|
|
const PAIR_GAP = 25;
|
|
|
|
type SingleLineData = Extract<
|
|
LetterTracingData,
|
|
{ mode: 'letter-tracing-half' }
|
|
>;
|
|
|
|
/**
|
|
* 单字母逐行绘制:
|
|
* 13 行四线三格横跨整页宽度,每行按 7 组位置预留空间。
|
|
* 前 4 组展示大小写字母(Aa),其余位置留空供用户书写。
|
|
* 颜色递进:黑色 → 浅红 → 半透明浅红 → 虚线字体+半透明浅红。
|
|
*/
|
|
export default class HalfLetterDraw extends BaseDrawService {
|
|
private letterSizes: LetterFontSizes =
|
|
calcLetterFontSizes(FOUR_LINE_GRID_H);
|
|
|
|
private dashedSizes: LetterFontSizes = calcLetterFontSizes(
|
|
FOUR_LINE_GRID_H,
|
|
PRINT_CLEARLY_DASHED,
|
|
);
|
|
|
|
async draw(data: SingleLineData) {
|
|
this.prepareDraw();
|
|
await Promise.all([
|
|
this.drawHeaderAndDivider(),
|
|
loadLetterFont(PRINT_CLEARLY_DASHED),
|
|
]);
|
|
this.drawContent(data.rows);
|
|
this.drawPrintFooter();
|
|
}
|
|
|
|
private drawContent(rows: SingleLineRow[]) {
|
|
const M = 24;
|
|
const lineW = this.canvasWidth - M * 2;
|
|
const rowCount = rows.length;
|
|
|
|
const footerReserve = 56;
|
|
const availableH =
|
|
this.canvasHeight - this.currentY - footerReserve - 12;
|
|
const rowGap = Math.max(
|
|
4,
|
|
(availableH - rowCount * FOUR_LINE_GRID_H) / (rowCount + 1),
|
|
);
|
|
const y0 = this.currentY + rowGap;
|
|
|
|
const slotW = lineW / SLOTS_PER_ROW;
|
|
|
|
for (let i = 0; i < rowCount; i++) {
|
|
const y = y0 + i * (FOUR_LINE_GRID_H + rowGap);
|
|
|
|
drawFourLineGrid(this.ctx, M, y, lineW, FOUR_LINE_GRID_H);
|
|
|
|
const row = rows[i];
|
|
for (let j = 0; j < row.cells.length; j++) {
|
|
const cell = row.cells[j];
|
|
if (!cell) continue;
|
|
|
|
const pairCx = M + 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();
|
|
}
|
|
}
|
|
}
|
|
}
|