/** * 绘制工具集合(后续可继续扩展其他通用绘制方法) */ import { ACTIVE_FONT_PROFILE, getLetterMetrics, type FontProfile, } from '../data/fontProfiles'; // ── 四线三格统一高度(所有页面共用) ── export const FOUR_LINE_GRID_H = 43; // ── 英语字母字体集合 ── export const TOY_FONT_LETTER = 'ToyLetterFont'; let _fontLoaded = false; export function loadLetterFont(): Promise { if (_fontLoaded) return Promise.resolve(); return new Promise((resolve, reject) => { wx.loadFontFace({ family: TOY_FONT_LETTER, source: `url("${ACTIVE_FONT_PROFILE.url}")`, scopes: ['native'], success: () => { _fontLoaded = true; resolve(); }, fail: (err) => { console.error('loadFontFace failed', err); reject(err); }, }); }); } // ── 向后兼容:LetterFontSizes 类型保留,供外部已有调用使用 ── export type LetterFontSizes = { /** 字体配置(新机制) */ _profile: FontProfile; /** gridH(用于运行时计算) */ _gridH: number; }; /** * 根据四线三格总高度,构建 LetterFontSizes。 * 内部持有 FontProfile 引用,按字母查表计算。 */ export function calcLetterFontSizes(gridH: number): LetterFontSizes { return { _profile: ACTIVE_FONT_PROFILE, _gridH: gridH, }; } /** 根据字母和字体配置,计算对应 fontSize */ export function getLetterFontSize( letter: string, sizes: LetterFontSizes, ): number { const metrics = getLetterMetrics(letter, sizes._profile); return sizes._gridH * metrics.scale; } /** 根据字母和字体配置,计算基线 Y 偏移修正(px) */ function getLetterBaselineOffset( letter: string, sizes: LetterFontSizes, ): number { const metrics = getLetterMetrics(letter, sizes._profile); return sizes._gridH * metrics.baselineOffset; } // ── 向后兼容:导出 DESCENDERS 集合 ── export { DESCENDERS } from '../data/fontProfiles'; /** * 在四线三格中绘制单个字母(基线固定在 y + 2h/3 + baselineOffset)。 * * @param cx 字母水平中心 * @param gridY 四线三格顶线 Y * @param gridH 四线三格总高度 * @param sizes 预计算的字号(由 calcLetterFontSizes 生成) */ export function drawLetterInFourLineGrid( ctx: RenderingContext, letter: string, cx: number, gridY: number, gridH: number, sizes: LetterFontSizes, options?: { fontFamily?: string; color?: string; bold?: boolean; }, ) { const fontFamily = options?.fontFamily ?? `${TOY_FONT_LETTER}, Roboto, sans-serif`; const color = options?.color ?? '#1a1a1a'; const bold = options?.bold ?? false; const baselineY = gridY + (gridH * 2) / 3 + getLetterBaselineOffset(letter, sizes); const fontSize = getLetterFontSize(letter, sizes); ctx.save(); ctx.font = `${bold ? 'bold ' : ''}${fontSize}px ${fontFamily}`; ctx.fillStyle = color; ctx.textAlign = 'center'; ctx.textBaseline = 'alphabetic'; ctx.fillText(letter, cx, baselineY); ctx.restore(); } export type FourLineGridStyle = { /** 顶线/底线颜色 */ ink?: string; /** 中间两条虚线颜色 */ middleInk?: string; /** 线宽 */ lineWidth?: number; /** 虚线样式 */ dash?: number[]; }; /** * 四线三格(通用) * - 顶/底:实线 * - 中间两条:虚线 */ export function drawFourLineGrid( ctx: RenderingContext, x: number, y: number, w: number, h: number, style?: FourLineGridStyle, ) { const ink = style?.ink ?? '#322E25'; const middleInk = style?.middleInk ?? 'rgba(50, 46, 37, 0.3)'; const lineWidth = style?.lineWidth ?? 1; const dash = style?.dash ?? [4, 4]; const yTop = y; const y1 = y + h / 3; const y2 = y + (h * 2) / 3; const yBot = y + h; ctx.strokeStyle = ink; ctx.lineWidth = lineWidth; ctx.setLineDash([]); ctx.beginPath(); ctx.moveTo(x, yTop); ctx.lineTo(x + w, yTop); ctx.stroke(); ctx.strokeStyle = middleInk; ctx.setLineDash(dash); ctx.beginPath(); ctx.moveTo(x, y1); ctx.lineTo(x + w, y1); ctx.stroke(); ctx.beginPath(); ctx.moveTo(x, y2); ctx.lineTo(x + w, y2); ctx.stroke(); ctx.strokeStyle = ink; ctx.setLineDash([]); ctx.beginPath(); ctx.moveTo(x, yBot); ctx.lineTo(x + w, yBot); ctx.stroke(); }