200 lines
6.0 KiB
TypeScript
200 lines
6.0 KiB
TypeScript
/**
|
||
* 九九乘法表绘制服务
|
||
*/
|
||
|
||
import { BaseDrawService } from '../../../core/draw/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;
|