diff --git a/miniprogram/app.json b/miniprogram/app.json index 019b315..d8f7bd5 100644 --- a/miniprogram/app.json +++ b/miniprogram/app.json @@ -18,7 +18,8 @@ "compare/compare", "countingSelect/countingSelect", "numberDecompose/numberDecompose", - "numberSort/numberSort" + "numberSort/numberSort", + "numberObjectMatch/numberObjectMatch" ], "independent": false }, @@ -34,7 +35,8 @@ "matchConnect/matchConnect", "lineRecognition/lineRecognition", "gridReasoning/gridReasoning", - "codeConnect/codeConnect" + "codeConnect/codeConnect", + "colorShapeMatch/colorShapeMatch" ], "independent": false } diff --git a/miniprogram/assets/focusEntrance/color-shape-match.png b/miniprogram/assets/focusEntrance/color-shape-match.png new file mode 100644 index 0000000..0edd784 Binary files /dev/null and b/miniprogram/assets/focusEntrance/color-shape-match.png differ diff --git a/miniprogram/assets/mathEntrance/number-object-match.png b/miniprogram/assets/mathEntrance/number-object-match.png new file mode 100644 index 0000000..ba9d759 Binary files /dev/null and b/miniprogram/assets/mathEntrance/number-object-match.png differ diff --git a/miniprogram/constants/colors.ts b/miniprogram/constants/colors.ts index da07eae..e63e88a 100644 --- a/miniprogram/constants/colors.ts +++ b/miniprogram/constants/colors.ts @@ -127,6 +127,28 @@ export function getRandomNumberColor(): string { return colors[Math.floor(Math.random() * colors.length)]; } +/** + * 从 NUMBER_COLORS 中随机获取指定数量的不重复颜色 + * @param count 需要获取的颜色数量 + * @returns 不重复的颜色数组 + */ +export function getRandomUniqueNumberColors(count: number): string[] { + const allColors = getNumberColors(); + if (count >= allColors.length) { + // 如果需要的数量大于等于总数,返回打乱后的所有颜色 + return [...allColors].sort(() => Math.random() - 0.5); + } + + // 使用 Set 确保不重复 + const selectedColors = new Set(); + while (selectedColors.size < count) { + const randomIndex = Math.floor(Math.random() * allColors.length); + selectedColors.add(allColors[randomIndex]); + } + + return Array.from(selectedColors); +} + export const PAPER_SIZE = { A4: { // width: 2480, diff --git a/miniprogram/constants/focusFunctions.ts b/miniprogram/constants/focusFunctions.ts index c78488a..439234c 100644 --- a/miniprogram/constants/focusFunctions.ts +++ b/miniprogram/constants/focusFunctions.ts @@ -9,14 +9,14 @@ export interface FocusFunctionType { } export const FOCUS_FUNCTION_TYPES: FocusFunctionType[] = [ - // 形状识别 + // 根据颜色画图形 { - id: 'shape-recognition', - page: 'shape', - title: '识别形状', - desc: '识别形状,涂一涂', - icon: '🔍', - img: '/assets/focusEntrance/shape-recognition.png', + id: 'color-shape-match', + page: 'colorShapeMatch', + title: '根据颜色画图形', + desc: '根据颜色画出对应的图形', + icon: '🎯', + img: '/assets/focusEntrance/color-shape-match.png', }, // 图形符号配对 { @@ -27,6 +27,15 @@ export const FOCUS_FUNCTION_TYPES: FocusFunctionType[] = [ icon: '🔗', img: '/assets/focusEntrance/shape-symbol.png', }, + // 形状识别 + { + id: 'shape-recognition', + page: 'shape', + title: '识别形状', + desc: '识别形状,涂一涂', + icon: '🔍', + img: '/assets/focusEntrance/shape-recognition.png', + }, // 方位涂涂乐 { id: 'position-coloring', @@ -54,6 +63,7 @@ export const FOCUS_FUNCTION_TYPES: FocusFunctionType[] = [ icon: '🔗', img: '/assets/focusEntrance/match-connect.png', }, + // 线条识别 { id: 'line-recognition', diff --git a/miniprogram/constants/mathFunctions.ts b/miniprogram/constants/mathFunctions.ts index 9073806..987e9c7 100644 --- a/miniprogram/constants/mathFunctions.ts +++ b/miniprogram/constants/mathFunctions.ts @@ -42,6 +42,15 @@ export const MATH_FUNCTION_TYPES: MathFunctionType[] = [ icon: '🔗', img: '/assets/mathEntrance/count-match.png', }, + // 数物对应 + { + id: 'number-object-match', + page: 'numberObjectMatch', + title: '数物对应', + desc: '连线相同数量的物品和数字', + icon: '🔗', + img: '/assets/mathEntrance/number-object-match.png', + }, { id: 'counting-select', page: 'countingSelect', diff --git a/miniprogram/focusPages/colorShapeMatch/colorShapeMatch.json b/miniprogram/focusPages/colorShapeMatch/colorShapeMatch.json new file mode 100644 index 0000000..64af3d7 --- /dev/null +++ b/miniprogram/focusPages/colorShapeMatch/colorShapeMatch.json @@ -0,0 +1,13 @@ +{ + "navigationBarTitleText": "根据颜色画图形", + "navigationBarBackgroundColor": "#FFD719", + "homeButton": true, + "backgroundColor": "#F6F6F6", + "enablePullDownRefresh": false, + "usingComponents": { + "toy-button": "../../ui/button/button", + "share-guide-popup": "../../components/share-guide-popup/share-guide-popup", + "math-bottom-buttons": "../../components/math-bottom-buttons/math-bottom-buttons", + "draw-ad": "../../components/draw-ad/draw-ad" + } +} diff --git a/miniprogram/focusPages/colorShapeMatch/colorShapeMatch.ts b/miniprogram/focusPages/colorShapeMatch/colorShapeMatch.ts new file mode 100644 index 0000000..c7bf2c5 --- /dev/null +++ b/miniprogram/focusPages/colorShapeMatch/colorShapeMatch.ts @@ -0,0 +1,132 @@ +import ColorShapeMatchDraw from '../shared/service/colorShapeMatchDraw'; +import { createFocusPage } from '../shared/common/focusPageMixin'; +import { ColorShapeMatchData } from '../shared/service/colorShapeMatchDraw'; +import { SHAPE_SYMBOL_SHAPES } from '../shared/shapes/shapeSymbolShapes'; +import { getRandomUniqueNumberColors } from '../../constants/colors'; + +createFocusPage({ + canvas: null as Canvas | null, + ctx: null as RenderingContext | null, + boxHeight: 0, + boxWidth: 0, + drawService: null as ColorShapeMatchDraw | null, + gridData: null as ColorShapeMatchData | null, + + data: { + pageTitle: '根据颜色画图形', + functionId: '', + hasContent: false, + showShareDialog: false, + }, + + onLoad(options: { id?: string }) { + const functionId = options.id || 'color-shape-match'; + this.setData({ + functionId, + }); + this.initPageInfo(functionId, '根据颜色画图形'); + }, + + onReady() { + this.initCanvas({ + createDrawService: ( + canvas: Canvas, + ctx: RenderingContext, + options?: Record, + ) => { + return new ColorShapeMatchDraw(canvas, ctx, options); + }, + drawServiceOptions: { + title: this.data.pageTitle, + subTitle: '根据颜色画出对应的图形', + functionId: this.data.functionId, + }, + onCanvasReady: () => { + // 初始随机生成 + this.onRandom(); + }, + }); + }, + + /** + * 绘制Canvas内容 + */ + async drawCanvas() { + if (!this.ctx || !this.drawService || !this.gridData) { + return; + } + + try { + await this.drawService.draw(this.gridData); + this.setData({ hasContent: true }); + } catch (error) { + console.error('绘制失败:', error); + this.setData({ hasContent: false }); + } + }, + + /** + * 随机生成 + */ + onRandom() { + // 从所有图形中随机选择4个 + const shapes = [...SHAPE_SYMBOL_SHAPES].filter( + (shape) => shape.id !== 'cross', + ); + const selectedShapes = shapes + .sort(() => Math.random() - 0.5) + .slice(0, 4); + + // 获取4个不重复的颜色 + const colors = getRandomUniqueNumberColors(4); + + // 创建阅览区域的数据,过滤掉 cross + const legendItems = selectedShapes.map((shape, index) => ({ + shapeId: shape.id, + color: colors[index], + })); + + // 创建练习区域的数据(5行5列,共25个格子) + // 随机填充这4种颜色,确保每种颜色至少出现一次 + const practiceGrid: Array> = []; + const allColors: (string | null)[] = new Array(25).fill(null); + + // 先随机选择4个位置,每个位置分配一种颜色(确保每种颜色至少出现一次) + const positions: number[] = []; + for (let i = 0; i < 25; i++) { + positions.push(i); + } + const shuffledPositions = [...positions].sort( + () => Math.random() - 0.5, + ); + + // 前4个位置分配4种颜色 + for (let i = 0; i < 4; i++) { + allColors[shuffledPositions[i]] = colors[i]; + } + + // 剩余21个位置随机分配这4种颜色 + for (let i = 4; i < 25; i++) { + const randomColor = + colors[Math.floor(Math.random() * colors.length)]; + allColors[shuffledPositions[i]] = randomColor; + } + + // 转换为5x5的二维数组 + for (let row = 0; row < 5; row++) { + const practiceRow: Array = []; + for (let col = 0; col < 5; col++) { + const index = row * 5 + col; + practiceRow.push(allColors[index]); + } + practiceGrid.push(practiceRow); + } + + this.gridData = { + legendItems, + practiceGrid, + }; + + this.drawCanvas(); + }, +}); diff --git a/miniprogram/focusPages/colorShapeMatch/colorShapeMatch.wxml b/miniprogram/focusPages/colorShapeMatch/colorShapeMatch.wxml new file mode 100644 index 0000000..3b70e13 --- /dev/null +++ b/miniprogram/focusPages/colorShapeMatch/colorShapeMatch.wxml @@ -0,0 +1,6 @@ + + + +