Files
doodle-mini/miniprogram/mathPages/missingNumber/missingNumber.ts
T
2025-12-11 13:02:44 +08:00

199 lines
5.5 KiB
TypeScript

import { getRandomNumberColor } from '../../constants/colors';
import MissingNumberDraw from '../shared/service/missingNumberDraw';
import {
createMathPage,
CanvasDataState,
} from '../shared/common/mathPageMixin';
createMathPage({
canvas: null as Canvas | null,
ctx: null as RenderingContext | null,
boxHeight: 0,
boxWidth: 0,
drawService: null as MissingNumberDraw | null,
missingNumberData: null as {
grids: Array<{
numbers: (number | null)[];
colors: (string | null)[];
}>;
maxNumber: number;
} | null,
data: {
pageTitle: '填上缺少的数字',
subTitle: '在数字序列中找出并填写缺失的数字',
functionId: '',
hasContent: false,
showShareDialog: false,
showTypeSelector: true,
currentMode: 10,
currentModeName: '10以内',
typeActions: [
{ name: '10以内', value: 10 },
{ name: '20以内', value: 20 },
{ name: '40以内', value: 40 },
{ name: '50以内', value: 50 },
{ name: '80以内', value: 80 },
{ name: '100以内', value: 100 },
{ name: '120以内', value: 120 },
],
} as CanvasDataState & {
showTypeSelector: boolean;
currentMode: number;
currentModeName: string;
typeActions: Array<{ name: string; value: number }>;
},
onLoad(options: { id?: string; mode?: number }) {
const functionId = options.id || 'missing-number';
this.initPageInfo(functionId, '填上缺少的数字');
this.setData({
currentMode: options.mode || 10,
currentModeName: options.mode ? `${options.mode}以内` : '10以内',
});
},
onReady() {
this.initCanvas({
createDrawService: (
canvas: Canvas,
ctx: RenderingContext,
options?: Record<string, any>,
) => {
return new MissingNumberDraw(canvas, ctx, options);
},
drawServiceOptions: {
subTitle: this.data.subTitle,
},
onCanvasReady: () => {
// Canvas 初始化完成后,生成初始数据
this.onRandom();
},
});
},
/**
* 绘制Canvas内容
*/
async drawCanvas() {
if (!this.ctx || !this.drawService || !this.missingNumberData) {
return;
}
try {
await this.drawService.draw(
this.missingNumberData,
String(this.data.currentMode),
);
this.setData({ hasContent: true });
} catch (error) {
console.error('绘制失败:', error);
this.setData({ hasContent: false });
}
},
/**
* 随机生成
*/
onRandom() {
const maxNumber = this.data.currentMode;
this.generateMissingNumberData(maxNumber);
this.drawCanvas();
},
/**
* 生成缺失数字数据
*/
generateMissingNumberData(maxNumber: number) {
const grids: Array<{
numbers: (number | null)[];
colors: (string | null)[];
}> = [];
const gridMap = {
10: {
gridCount: 3,
},
20: {
gridCount: 2,
},
40: {
gridCount: 2,
},
50: {
gridCount: 2,
},
80: {
gridCount: 1,
},
100: {
gridCount: 1,
},
120: {
gridCount: 1,
},
};
const { gridCount } = gridMap[maxNumber as keyof typeof gridMap];
// 生成多个网格
for (let gridIndex = 0; gridIndex < gridCount; gridIndex++) {
let startNumber = 1;
let endNumber = maxNumber;
const actualNumbersPerGrid = endNumber - startNumber + 1;
const numbers: number[] = Array.from(
{ length: actualNumbersPerGrid },
(_, i) => startNumber + i,
);
// 随机隐藏一部分数字(隐藏40-60%)
const hideCount = Math.floor(
actualNumbersPerGrid * (0.4 + Math.random() * 0.2),
);
const hiddenIndices = new Set<number>();
while (hiddenIndices.size < hideCount) {
const randomIndex = Math.floor(
Math.random() * actualNumbersPerGrid,
);
hiddenIndices.add(randomIndex);
}
const gridNumbers: (number | null)[] = numbers.map((num, index) =>
hiddenIndices.has(index) ? null : num,
);
// 为每个数字分配颜色(包括null位置)
const gridColors: (string | null)[] = gridNumbers.map((num) =>
num ? this.getRandomNumberColor() : null,
);
grids.push({ numbers: gridNumbers, colors: gridColors });
}
this.missingNumberData = {
grids,
maxNumber,
};
},
/**
* 获取随机数字颜色
*/
getRandomNumberColor(): string {
return getRandomNumberColor();
},
/** 选择类型 */
onSelectType(event: any) {
const { name, value } = event.detail;
this.setData({
currentMode: value,
currentModeName: name,
});
// 重新生成数据
this.onRandom();
},
});