/** * 九九乘法表绘制服务 */ import { BaseDrawService } from '../../../service/baseDraw'; import { getRandomUniqueNumberColors } from '../../../constants/colors'; /** * 数字转中文(1-99) */ function numberToChinese(num: number): string { const digits = ['', '一', '二', '三', '四', '五', '六', '七', '八', '九']; const tens = [ '', '十', '二十', '三十', '四十', '五十', '六十', '七十', '八十', '九十', ]; if (num === 0) return '零'; if (num < 10) return digits[num]; if (num === 10) return '十'; if (num < 20) return '十' + digits[num % 10]; if (num % 10 === 0) return tens[Math.floor(num / 10)]; return tens[Math.floor(num / 10)] + digits[num % 10]; } /** * 生成九九乘法表汉字口诀 * @param a 第一个乘数 * @param b 第二个乘数 * @param result 结果 */ function getChineseFormula(a: number, b: number, result: number): string { const aChinese = numberToChinese(a); const bChinese = numberToChinese(b); const resultChinese = numberToChinese(result); return `${aChinese}${bChinese}得${resultChinese}`; } /** * 九九乘法表数据 */ export interface MultiplicationTableData { // 不需要额外数据,九九乘法表是固定的 } /** * 九九乘法表绘制服务 */ class MultiplicationTableDraw extends BaseDrawService { tableData: MultiplicationTableData | null = null; constructor( canvas: Canvas, ctx: RenderingContext, options?: Record, ) { super(canvas, ctx, options); this.tableData = null; } /** * 绘制九九乘法表内容 */ async draw(tableData?: MultiplicationTableData) { this.tableData = tableData || {}; this.prepareDraw(); await this.drawHeaderAndDivider(); await this.drawContent({ canvas: this.canvas, ctx: this.ctx, canvasWidth: this.canvasWidth, startY: this.currentY, }); } /** * 绘制内容区域 */ private async drawContent(params: { canvas: WechatMiniprogram.Canvas; ctx: RenderingContext; canvasWidth: number; startY: number; }): Promise { const { ctx, canvasWidth, startY } = params; // 获取9种颜色(1-9列,每列一种颜色) const colors = getRandomUniqueNumberColors(9); // 布局参数 const margin = 30; // 左右边距 const topMargin = 40; // 顶部间距 const sectionSpacing = 40; // 上下两部分之间的间距 const dividerMargin = 20; // 分割线左右边距 // 计算可用宽度 const availableWidth = canvasWidth - margin * 2; const cellWidth = availableWidth / 9; // 每列宽度 const rowHeight = 26; // 每行高度(减小行高) const fontSize = 12; // 字体大小(减小字体) let currentY = startY + topMargin; // ========== 绘制数字版九九乘法表 ========== const numberTableStartY = currentY; // 绘制表格边框和内容 for (let row = 1; row <= 9; row++) { const rowY = numberTableStartY + (row - 1) * rowHeight; for (let col = 1; col <= row; col++) { const colX = margin + (col - 1) * cellWidth; const color = colors[col - 1]; // 绘制单元格边框 ctx.strokeStyle = '#333'; ctx.lineWidth = 1; ctx.strokeRect(colX, rowY, cellWidth, rowHeight); // 生成公式:col x row = result const result = col * row; const formula = `${col}×${row}=${result}`; // 绘制公式(带颜色) ctx.fillStyle = color; ctx.font = `bold ${fontSize}px "Microsoft Yahei"`; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText( formula, colX + cellWidth / 2, rowY + rowHeight / 2, ); } } // 数字版结束位置 const numberTableEndY = numberTableStartY + 9 * rowHeight; currentY = numberTableEndY + sectionSpacing; // ========== 绘制虚线分割线 ========== this.drawLine( dividerMargin, currentY, canvasWidth - dividerMargin, currentY, { isDashed: true, dashPattern: [4, 4], color: '#999', lineWidth: 1, }, ); currentY += sectionSpacing; // ========== 绘制汉字版九九乘法表 ========== const chineseTableStartY = currentY; const hzFontSize = 8; // 绘制表格边框和内容 for (let row = 1; row <= 9; row++) { const rowY = chineseTableStartY + (row - 1) * rowHeight; for (let col = 1; col <= row; col++) { const colX = margin + (col - 1) * cellWidth; const color = colors[col - 1]; // 使用和数字版相同的颜色 // 绘制单元格边框 ctx.strokeStyle = '#333'; ctx.lineWidth = 1; ctx.strokeRect(colX, rowY, cellWidth, rowHeight); // 生成汉字口诀 const result = col * row; const chineseFormula = getChineseFormula(col, row, result); // 绘制汉字口诀(带颜色) ctx.fillStyle = color; ctx.font = `bold ${hzFontSize}px "Microsoft Yahei"`; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText( chineseFormula, colX + cellWidth / 2, rowY + rowHeight / 2, ); } } } } export default MultiplicationTableDraw;