import { BaseDrawService } from '../../core/draw/baseDraw'; import { GRID_COLORS, GRID_DASH, TRACING_COLORS, } from '../../core/data/tracingStyles'; import { TONEOZ_PINYIN, fontFamilyOf } from '../../core/font/fontProfiles'; import { PINYIN_STYLE } from './pinyinConstants'; export abstract class PinyinBaseDraw extends BaseDrawService { /** * 绘制一行四线三格 */ protected drawFourLineRow( x: number, y: number, cols: number, cellW: number, cellH: number, ) { const ctx = this.ctx; const totalW = cols * cellW; const yTop = y; const y1 = y + cellH / 3; const y2 = y + (cellH * 2) / 3; const yBot = y + cellH; ctx.lineWidth = 1; // 外边框(上下) ctx.strokeStyle = GRID_COLORS.border; ctx.setLineDash([]); ctx.beginPath(); ctx.moveTo(x, yTop); ctx.lineTo(x + totalW, yTop); ctx.stroke(); ctx.beginPath(); ctx.moveTo(x, yBot); ctx.lineTo(x + totalW, yBot); ctx.stroke(); // 中间虚线 ctx.strokeStyle = GRID_COLORS.middleLine; ctx.setLineDash([...GRID_DASH]); ctx.beginPath(); ctx.moveTo(x, y1); ctx.lineTo(x + totalW, y1); ctx.stroke(); ctx.beginPath(); ctx.moveTo(x, y2); ctx.lineTo(x + totalW, y2); ctx.stroke(); // 垂直分割线 ctx.strokeStyle = GRID_COLORS.border; ctx.setLineDash([]); for (let i = 0; i <= cols; i++) { const vx = x + i * cellW; ctx.beginPath(); ctx.moveTo(vx, yTop); ctx.lineTo(vx, yBot); ctx.stroke(); } } /** * 绘制单个封闭四线三格(用于逐格绘制场景,如每日打卡) */ protected drawFourLineGrid( x: number, y: number, w: number, h: number, ) { const ctx = this.ctx; const y1 = y + h / 3; const y2 = y + (h * 2) / 3; ctx.save(); ctx.strokeStyle = GRID_COLORS.border; ctx.lineWidth = 1; ctx.setLineDash([]); ctx.strokeRect(x, y, w, h); ctx.strokeStyle = GRID_COLORS.middleLine; ctx.setLineDash([...GRID_DASH]); ctx.beginPath(); ctx.moveTo(x, y1); ctx.lineTo(x + w, y1); ctx.moveTo(x, y2); ctx.lineTo(x + w, y2); ctx.stroke(); ctx.restore(); } /** * 在四线三格中绘制拼音文本 */ protected drawPinyinText( pinyin: string, cx: number, gridY: number, gridH: number, fontSizeRatio: number = PINYIN_STYLE.PINYIN_FONT_SIZE_RATIO, ) { const ctx = this.ctx; const fontSize = Math.round(gridH * fontSizeRatio); const baselineY = gridY + (gridH * 2) / 3; ctx.save(); ctx.font = `${fontSize}px ${fontFamilyOf(TONEOZ_PINYIN)}`; ctx.fillStyle = TRACING_COLORS.guide; ctx.textAlign = 'center'; ctx.textBaseline = 'alphabetic'; ctx.fillText(pinyin, cx, baselineY); ctx.restore(); } }