feat: 修改字母描红逻辑,添加字母手写字体
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { ALPHABET_BY_LETTER, LETTERS_UPPER } from '../../../core/data/alphabet';
|
||||
import { ALPHABET_BY_LETTER, LETTERS_UPPER } from '../data/alphabet';
|
||||
|
||||
/** 字母描红的布局模式(与产品文档四类练习一致) */
|
||||
export type LetterTracingMode =
|
||||
@@ -43,6 +43,12 @@ export interface TracingRow {
|
||||
cells: TracingCell[];
|
||||
}
|
||||
|
||||
/** Highlight It 格子数据(3×6 网格,混入目标字母) */
|
||||
export interface HighlightGrid {
|
||||
rows: string[][];
|
||||
targetLetter: string;
|
||||
}
|
||||
|
||||
/** 看图描红教学区 */
|
||||
export interface TeachingBlock {
|
||||
upper: string;
|
||||
@@ -50,13 +56,21 @@ export interface TeachingBlock {
|
||||
word: string;
|
||||
sentence: string;
|
||||
emoji: string;
|
||||
/** 字母笔顺图路径(/englishPages/shared/assets/letter/X.png) */
|
||||
letterImgPath: string;
|
||||
/** 配图路径(/englishPages/shared/assets/letterImgs/Word.png) */
|
||||
wordImgPath: string;
|
||||
}
|
||||
|
||||
export type LetterTracingData =
|
||||
| {
|
||||
mode: 'picture-tracing';
|
||||
teaching: TeachingBlock;
|
||||
rows: TracingRow[];
|
||||
highlightGrid: HighlightGrid;
|
||||
/** Trace It 区域使用的字母笔顺图路径(同 teaching.letterImgPath) */
|
||||
traceImgPath: string;
|
||||
/** 下部 4 行四线三格(无字符填充,纯空行) */
|
||||
tracingLineCount: number;
|
||||
}
|
||||
| {
|
||||
mode: 'case-pairing';
|
||||
@@ -80,6 +94,33 @@ export function normalizeLetter(c: string): string {
|
||||
return u.length ? u[0] : 'A';
|
||||
}
|
||||
|
||||
/** 构建 Highlight It 的 3×6 随机字母网格,保证混入 2~5 个目标字母 */
|
||||
function buildHighlightGrid(
|
||||
target: string,
|
||||
gridRows: number,
|
||||
gridCols: number,
|
||||
): HighlightGrid {
|
||||
const total = gridRows * gridCols;
|
||||
const targetCount = 2 + Math.floor(Math.random() * 4); // 2~5
|
||||
const others = LETTERS_UPPER.filter((l) => l !== target);
|
||||
|
||||
const chars: string[] = [];
|
||||
for (let i = 0; i < targetCount; i++) chars.push(target);
|
||||
for (let i = targetCount; i < total; i++) {
|
||||
chars.push(others[Math.floor(Math.random() * others.length)]);
|
||||
}
|
||||
for (let i = chars.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[chars[i], chars[j]] = [chars[j], chars[i]];
|
||||
}
|
||||
|
||||
const rows: string[][] = [];
|
||||
for (let r = 0; r < gridRows; r++) {
|
||||
rows.push(chars.slice(r * gridCols, (r + 1) * gridCols));
|
||||
}
|
||||
return { rows, targetLetter: target };
|
||||
}
|
||||
|
||||
function buildCells(
|
||||
char: string,
|
||||
count: number,
|
||||
@@ -165,22 +206,32 @@ export function generateLetterTracing(
|
||||
const meta = ALPHABET_BY_LETTER[key] ?? ALPHABET_BY_LETTER.A;
|
||||
const upper = key;
|
||||
const lower = key.toLowerCase();
|
||||
|
||||
const hasLetterAsset = key === 'A' || key === 'B';
|
||||
const letterFile = hasLetterAsset ? key : 'A';
|
||||
const letterImgPath = `/englishPages/shared/assets/letter/${letterFile}.png`;
|
||||
|
||||
const wordImgPath = `/englishPages/shared/assets/letterImgs/Apple.png`;
|
||||
|
||||
const teaching: TeachingBlock = {
|
||||
upper,
|
||||
lower,
|
||||
word: meta.word,
|
||||
sentence: `${upper} is for ${meta.word}`,
|
||||
emoji: meta.emoji,
|
||||
letterImgPath,
|
||||
wordImgPath,
|
||||
};
|
||||
|
||||
const highlightGrid = buildHighlightGrid(upper, 3, 6);
|
||||
|
||||
return {
|
||||
mode: 'picture-tracing',
|
||||
teaching,
|
||||
highlightGrid,
|
||||
traceImgPath: letterImgPath,
|
||||
tracingLineCount: 8,
|
||||
};
|
||||
const rows: TracingRow[] = [
|
||||
rowForChar(upper, repetitions, fadePattern),
|
||||
rowForChar(upper, repetitions, fadePattern),
|
||||
rowForChar(upper, repetitions, fadePattern),
|
||||
rowForChar(lower, repetitions, fadePattern),
|
||||
rowForChar(lower, repetitions, fadePattern),
|
||||
rowForChar(lower, repetitions, fadePattern),
|
||||
];
|
||||
return { mode: 'picture-tracing', teaching, rows };
|
||||
}
|
||||
|
||||
if (mode === 'case-pairing') {
|
||||
@@ -189,12 +240,7 @@ export function generateLetterTracing(
|
||||
const pack = (letters: string[]) =>
|
||||
chunk(letters, 4).map((group) =>
|
||||
group.map((L) =>
|
||||
rowForChar(
|
||||
L,
|
||||
repetitions,
|
||||
fadePattern,
|
||||
L.toLowerCase(),
|
||||
),
|
||||
rowForChar(L, repetitions, fadePattern, L.toLowerCase()),
|
||||
),
|
||||
);
|
||||
return {
|
||||
@@ -227,9 +273,7 @@ export function generateLetterTracing(
|
||||
return {
|
||||
mode: 'overview',
|
||||
upperRows: overviewRowsFrom([...LETTERS_UPPER]),
|
||||
lowerRows: overviewRowsFrom(
|
||||
LETTERS_UPPER.map((L) => L.toLowerCase()),
|
||||
),
|
||||
lowerRows: overviewRowsFrom(LETTERS_UPPER.map((L) => L.toLowerCase())),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user