feat: 英语字母描红修改
This commit is contained in:
@@ -258,8 +258,8 @@ export const ALL_WORKSHEETS: WorksheetDefinition[] = [
|
||||
sheet(
|
||||
{
|
||||
id: 'letter-tracing-single',
|
||||
title: '字母学习页',
|
||||
desc: '单字母配图、阅读句与四线三格描红',
|
||||
title: '看图描红',
|
||||
desc: '单字母配图、例句与六行四线三格描红',
|
||||
category: 'english',
|
||||
page: 'letterTracing',
|
||||
subpackage: 'englishPages',
|
||||
@@ -280,7 +280,7 @@ export const ALL_WORKSHEETS: WorksheetDefinition[] = [
|
||||
instructionText: '看一看,读一读,再描一描',
|
||||
},
|
||||
generatorConfig: {
|
||||
mode: 'single-letter',
|
||||
mode: 'picture-tracing',
|
||||
letterCase: 'upper',
|
||||
selectedLetter: 'A',
|
||||
repetitions: 5,
|
||||
@@ -291,8 +291,8 @@ export const ALL_WORKSHEETS: WorksheetDefinition[] = [
|
||||
sheet(
|
||||
{
|
||||
id: 'letter-tracing-full',
|
||||
title: '26 字母描红',
|
||||
desc: '整页四线三格逐字母描红',
|
||||
title: '分栏对照',
|
||||
desc: '半组字母左大写右小写,每行四个',
|
||||
category: 'english',
|
||||
page: 'letterTracing',
|
||||
subpackage: 'englishPages',
|
||||
@@ -308,11 +308,15 @@ export const ALL_WORKSHEETS: WorksheetDefinition[] = [
|
||||
template: 'tracing-writing',
|
||||
generator: 'letter-tracing',
|
||||
sortOrder: 43,
|
||||
layoutConfig: { ...L.trace, instructionText: '沿虚线描写字母' },
|
||||
layoutConfig: {
|
||||
...L.trace,
|
||||
instructionText: '左栏大写、右栏小写,逐行对应描红',
|
||||
},
|
||||
generatorConfig: {
|
||||
mode: 'full-alphabet',
|
||||
letterCase: 'upper',
|
||||
repetitions: 8,
|
||||
mode: 'column-compare',
|
||||
letterCase: 'both',
|
||||
alphabetHalf: 'A-M',
|
||||
repetitions: 4,
|
||||
fadePattern: 'gradient',
|
||||
},
|
||||
},
|
||||
@@ -320,8 +324,8 @@ export const ALL_WORKSHEETS: WorksheetDefinition[] = [
|
||||
sheet(
|
||||
{
|
||||
id: 'letter-tracing-upper-lower',
|
||||
title: '大小写字母对照',
|
||||
desc: '上半部大写、下半部小写总览',
|
||||
title: '字母总览',
|
||||
desc: 'Uppercase / Lowercase 分区,9+9+8 行',
|
||||
category: 'english',
|
||||
page: 'letterTracing',
|
||||
subpackage: 'englishPages',
|
||||
@@ -340,10 +344,10 @@ export const ALL_WORKSHEETS: WorksheetDefinition[] = [
|
||||
layoutConfig: {
|
||||
...L.trace,
|
||||
columns: 13,
|
||||
instructionText: '认识大写和小写字母',
|
||||
instructionText: '认读全部大写与小写字母',
|
||||
},
|
||||
generatorConfig: {
|
||||
mode: 'upper-lower-split',
|
||||
mode: 'overview',
|
||||
letterCase: 'both',
|
||||
repetitions: 1,
|
||||
fadePattern: 'first-only',
|
||||
@@ -353,8 +357,8 @@ export const ALL_WORKSHEETS: WorksheetDefinition[] = [
|
||||
sheet(
|
||||
{
|
||||
id: 'letter-tracing-two-column',
|
||||
title: '字母描红(两列)',
|
||||
desc: 'A–M / N–Z 两列练习',
|
||||
title: '大小写配对',
|
||||
desc: '左 A–M、右 N–Z,每行四组大小写',
|
||||
category: 'english',
|
||||
page: 'letterTracing',
|
||||
subpackage: 'englishPages',
|
||||
@@ -376,8 +380,8 @@ export const ALL_WORKSHEETS: WorksheetDefinition[] = [
|
||||
instructionText: '沿虚线描写字母',
|
||||
},
|
||||
generatorConfig: {
|
||||
mode: 'two-column',
|
||||
letterCase: 'upper',
|
||||
mode: 'case-pairing',
|
||||
letterCase: 'both',
|
||||
repetitions: 4,
|
||||
fadePattern: 'gradient',
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@ import drawHeader from './drawHeader';
|
||||
* - 打印配置管理
|
||||
*/
|
||||
const LINE_COLOR = 'rgba(50, 46, 37, 0.4)';
|
||||
const LINE_WIDTH = 3;
|
||||
const LINE_WIDTH = 2;
|
||||
|
||||
export class BaseDrawService {
|
||||
canvas: WechatMiniprogram.Canvas;
|
||||
|
||||
@@ -24,7 +24,7 @@ const META_FONT_PX = 12;
|
||||
const META_UNDERLINE_GAP = 3;
|
||||
const TITLE_COLOR = '#322E25';
|
||||
const LINE_COLOR = 'rgba(50, 46, 37, 0.4)';
|
||||
const LINE_WIDTH = 3;
|
||||
const LINE_WIDTH = 2;
|
||||
const META_COLOR = '#7C766A';
|
||||
const META_ROW_MARGIN_X = 130;
|
||||
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
import {
|
||||
ALPHABET_BY_LETTER,
|
||||
LETTERS_UPPER,
|
||||
} from '../data/alphabet';
|
||||
|
||||
export type LetterTracingMode =
|
||||
| 'single-letter'
|
||||
| 'full-alphabet'
|
||||
| 'upper-lower-split'
|
||||
| 'two-column';
|
||||
|
||||
export type LetterCaseMode = 'upper' | 'lower' | 'both';
|
||||
|
||||
export interface LetterTracingGeneratorConfig {
|
||||
mode: LetterTracingMode;
|
||||
letterCase: LetterCaseMode;
|
||||
selectedLetter?: string;
|
||||
repetitions: number;
|
||||
fadePattern: 'gradient' | 'first-only';
|
||||
}
|
||||
|
||||
export interface TracingCell {
|
||||
char: string;
|
||||
opacity: number;
|
||||
isGuide: boolean;
|
||||
}
|
||||
|
||||
export interface TracingRow {
|
||||
displayChar: string;
|
||||
cells: TracingCell[];
|
||||
}
|
||||
|
||||
export interface TeachingBlock {
|
||||
upper: string;
|
||||
lower: string;
|
||||
word: string;
|
||||
sentence: string;
|
||||
emoji: string;
|
||||
}
|
||||
|
||||
export type LetterTracingData =
|
||||
| {
|
||||
mode: 'single-letter';
|
||||
teaching: TeachingBlock;
|
||||
rows: TracingRow[];
|
||||
}
|
||||
| {
|
||||
mode: 'full-alphabet';
|
||||
rows: TracingRow[];
|
||||
}
|
||||
| {
|
||||
mode: 'upper-lower-split';
|
||||
upperGlyphs: string[];
|
||||
lowerGlyphs: string[];
|
||||
}
|
||||
| {
|
||||
mode: 'two-column';
|
||||
leftRows: TracingRow[];
|
||||
rightRows: TracingRow[];
|
||||
};
|
||||
|
||||
function normalizeLetter(c: string): string {
|
||||
const u = c.trim().toUpperCase();
|
||||
return u.length ? u[0] : 'A';
|
||||
}
|
||||
|
||||
function buildCells(
|
||||
char: string,
|
||||
count: number,
|
||||
fadePattern: 'gradient' | 'first-only',
|
||||
): TracingCell[] {
|
||||
const n = Math.max(1, Math.min(12, count));
|
||||
const cells: TracingCell[] = [];
|
||||
for (let i = 0; i < n; i++) {
|
||||
let opacity: number;
|
||||
if (fadePattern === 'first-only') {
|
||||
opacity = i === 0 ? 1 : 0;
|
||||
} else if (n <= 1) {
|
||||
opacity = 1;
|
||||
} else {
|
||||
opacity = Math.max(0.12, 1 - i / (n - 1));
|
||||
}
|
||||
cells.push({ char, opacity, isGuide: i === 0 });
|
||||
}
|
||||
return cells;
|
||||
}
|
||||
|
||||
function rowForChar(
|
||||
ch: string,
|
||||
repetitions: number,
|
||||
fadePattern: 'gradient' | 'first-only',
|
||||
): TracingRow {
|
||||
return {
|
||||
displayChar: ch,
|
||||
cells: buildCells(ch, repetitions, fadePattern),
|
||||
};
|
||||
}
|
||||
|
||||
export function generateLetterTracing(
|
||||
config: LetterTracingGeneratorConfig,
|
||||
): LetterTracingData {
|
||||
const { mode, letterCase, repetitions, fadePattern } = config;
|
||||
|
||||
if (mode === 'single-letter') {
|
||||
const key = normalizeLetter(config.selectedLetter ?? 'A');
|
||||
const meta = ALPHABET_BY_LETTER[key] ?? ALPHABET_BY_LETTER.A;
|
||||
const upper = key;
|
||||
const lower = key.toLowerCase();
|
||||
const teaching: TeachingBlock = {
|
||||
upper,
|
||||
lower,
|
||||
word: meta.word,
|
||||
sentence: `${upper} is for ${meta.word}`,
|
||||
emoji: meta.emoji,
|
||||
};
|
||||
const rows: TracingRow[] = [
|
||||
rowForChar(upper, repetitions, fadePattern),
|
||||
rowForChar(lower, repetitions, fadePattern),
|
||||
];
|
||||
return { mode: 'single-letter', teaching, rows };
|
||||
}
|
||||
|
||||
if (mode === 'full-alphabet') {
|
||||
const rows = LETTERS_UPPER.map((L) => {
|
||||
const ch = letterCase === 'lower' ? L.toLowerCase() : L;
|
||||
return rowForChar(ch, repetitions, fadePattern);
|
||||
});
|
||||
return { mode: 'full-alphabet', rows };
|
||||
}
|
||||
|
||||
if (mode === 'upper-lower-split') {
|
||||
return {
|
||||
mode: 'upper-lower-split',
|
||||
upperGlyphs: [...LETTERS_UPPER],
|
||||
lowerGlyphs: LETTERS_UPPER.map((L) => L.toLowerCase()),
|
||||
};
|
||||
}
|
||||
|
||||
// two-column
|
||||
const left = LETTERS_UPPER.slice(0, 13);
|
||||
const right = LETTERS_UPPER.slice(13);
|
||||
const mapChar = (L: string) =>
|
||||
letterCase === 'lower' ? L.toLowerCase() : L;
|
||||
const leftRows = left.map((L) =>
|
||||
rowForChar(mapChar(L), repetitions, fadePattern),
|
||||
);
|
||||
const rightRows = right.map((L) =>
|
||||
rowForChar(mapChar(L), repetitions, fadePattern),
|
||||
);
|
||||
return { mode: 'two-column', leftRows, rightRows };
|
||||
}
|
||||
|
||||
/** 与 WorksheetDefinition.generatorConfig 合并后的运行时配置 */
|
||||
export function mergeLetterTracingConfig(
|
||||
base: Partial<LetterTracingGeneratorConfig>,
|
||||
overrides: Partial<LetterTracingGeneratorConfig>,
|
||||
): LetterTracingGeneratorConfig {
|
||||
return {
|
||||
mode: (overrides.mode ?? base.mode ?? 'single-letter') as LetterTracingMode,
|
||||
letterCase: (overrides.letterCase ??
|
||||
base.letterCase ??
|
||||
'upper') as LetterCaseMode,
|
||||
selectedLetter: overrides.selectedLetter ?? base.selectedLetter,
|
||||
repetitions: Math.max(
|
||||
1,
|
||||
(overrides.repetitions ?? base.repetitions ?? 5) as number,
|
||||
),
|
||||
fadePattern: (overrides.fadePattern ??
|
||||
base.fadePattern ??
|
||||
'gradient') as 'gradient' | 'first-only',
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user