feat:九九乘法表
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* 九九乘法表绘制服务
|
||||
*/
|
||||
|
||||
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<string, any>,
|
||||
) {
|
||||
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<void> {
|
||||
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;
|
||||
Reference in New Issue
Block a user