import GridDraw, { GridGroup } from '../shared/service/gridDraw'; import { createFocusPage } from '../shared/common/focusPageMixin'; import { GridDrawingData } from '../shared/service/gridDraw'; import { generateCompletePattern } from '../shared/utils/gridUtils'; import { ALL_3X3_SHAPES } from '../shared/shapes/gridShapes3x3'; import { ALL_5X5_SHAPES } from '../shared/shapes/gridShapes5x5'; import { ALL_7X7_SHAPES } from '../shared/shapes/gridShapes7x7'; import { ShapeTemplate, GridCell } from '../shared/types/gridTypes'; import { GridConfig } from '../shared/types/gridTypes'; import { FOCUS_FUNCTION_TYPES } from '../../constants/focusFunctions'; createFocusPage({ canvas: null as Canvas | null, ctx: null as RenderingContext | null, boxHeight: 0, boxWidth: 0, drawService: null as GridDraw | null, gridData: null as GridDrawingData | null, data: { pageTitle: '格子仿画 5×5', functionId: '', hasContent: false, showShareDialog: false, currentMode: '3x3', // '3x3', '5x5', '7x7' currentModeName: '3×3', subTitle: '', // 副标题,从配置中获取 typeActions: [ { name: '3×3', value: '3x3' }, { name: '5×5', value: '5x5' }, { name: '7×7', value: '7x7' }, ], }, onLoad(options: { id?: string; mode?: string }) { const functionId = options.id || 'grid-drawing'; const mode = options.mode || '3x3'; // 从参数中读取 mode,默认为 '3x3' // 根据 mode 设置对应的模式名称 const modeNameMap: Record = { '3x3': '3×3', '5x5': '5×5', '7x7': '7×7', }; const currentModeName = modeNameMap[mode] || '3×3'; // 根据 mode 查找配置,获取 desc 作为 subTitle const configItem = FOCUS_FUNCTION_TYPES.find( (item) => item.mode === mode && item.id?.startsWith('grid-drawing'), ); const subTitle = configItem?.desc || '在网格中填充颜色,形成各种形状'; this.setData({ pageTitle: `格子仿画 ${mode}`, functionId, currentMode: mode, currentModeName, subTitle, }); this.initPageInfo(functionId, '格子仿画'); }, onReady() { this.initCanvas({ createDrawService: ( canvas: Canvas, ctx: RenderingContext, options?: Record, ) => { return new GridDraw(canvas, ctx, options); }, drawServiceOptions: { title: this.data.pageTitle, subTitle: this.data.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 }); } }, /** * 检查两个图案是否相同(通过比较格子的位置和颜色) */ arePatternsEqual(cells1: GridCell[], cells2: GridCell[]): boolean { if (cells1.length !== cells2.length) { return false; } // 将格子转换为字符串键进行比较 const pattern1 = cells1 .map((c) => `${c.x},${c.y},${c.color}`) .sort() .join('|'); const pattern2 = cells2 .map((c) => `${c.x},${c.y},${c.color}`) .sort() .join('|'); return pattern1 === pattern2; }, /** * 生成不重复的图案组 */ generateUniqueGroups( allShapes: ShapeTemplate[], count: number, config: GridConfig, ): GridGroup[] { const groups: GridGroup[] = []; const usedPatterns = new Set(); // 用于存储已使用的图案签名 // 如果需要的数量超过可用形状数量,允许重复使用 const maxUniqueShapes = Math.min(count, allShapes.length); const availableShapes = [...allShapes]; // 复制数组以便打乱 // 打乱数组顺序 for (let i = availableShapes.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [availableShapes[i], availableShapes[j]] = [ availableShapes[j], availableShapes[i], ]; } // 生成不重复的图案 for (let i = 0; i < count; i++) { const shapeIndex = i % availableShapes.length; const shape = availableShapes[shapeIndex]; const cells = generateCompletePattern(shape, config); // 生成图案签名 const patternSignature = cells .map((c) => `${c.x},${c.y},${c.color}`) .sort() .join('|'); // 如果图案已存在,尝试下一个形状 if (usedPatterns.has(patternSignature)) { // 如果所有形状都用过了,允许重复 if (usedPatterns.size >= maxUniqueShapes) { // 使用当前形状,即使重复 groups.push({ filledCells: cells, emptyCells: [], }); continue; } else { // 尝试找到未使用的形状 let found = false; for (let j = 0; j < availableShapes.length; j++) { const nextShape = availableShapes[j]; const nextCells = generateCompletePattern( nextShape, config, ); const nextSignature = nextCells .map((c) => `${c.x},${c.y},${c.color}`) .sort() .join('|'); if (!usedPatterns.has(nextSignature)) { groups.push({ filledCells: nextCells, emptyCells: [], }); usedPatterns.add(nextSignature); found = true; break; } } if (!found) { // 如果找不到未使用的,使用当前形状 groups.push({ filledCells: cells, emptyCells: [], }); } } } else { // 图案未使用,添加到结果中 groups.push({ filledCells: cells, emptyCells: [], }); usedPatterns.add(patternSignature); } } return groups; }, /** * 随机生成 */ onRandom() { const mode = this.data.currentMode; let allShapes: ShapeTemplate[]; let config: GridConfig; let groupsPerRow: number; let totalRows: number; // 根据模式选择形状和配置 if (mode === '3x3') { allShapes = ALL_3X3_SHAPES; config = { rows: 3, cols: 3 }; groupsPerRow = 2; // 每行2组 totalRows = 4; // 总共3行 } else if (mode === '5x5') { allShapes = ALL_5X5_SHAPES; config = { rows: 5, cols: 5 }; groupsPerRow = 2; totalRows = 4; // 5x5可以展示2行 } else { // 7x7 allShapes = ALL_7X7_SHAPES; config = { rows: 7, cols: 7 }; groupsPerRow = 1; // 7x7每行1组 totalRows = 2; // 总共2行 } // 生成不重复的图案组 const totalGroups = groupsPerRow * totalRows; const groups = this.generateUniqueGroups( allShapes, totalGroups, config, ); this.gridData = { config, groups, groupsPerRow, totalRows, }; this.drawCanvas(); }, /** 选择类型 */ onSelectType(event: any) { const { name, value } = event.detail; // 根据 mode 查找配置,获取 desc 作为 subTitle const configItem = FOCUS_FUNCTION_TYPES.find( (item) => item.mode === value && item.id?.startsWith('grid-drawing'), ); const pageTitle = `格子仿画 ${value}`; const subTitle = configItem?.desc || '在网格中填充颜色,形成各种形状'; // 更新 pageTitle、currentMode、currentModeName 和 subTitle this.setData({ pageTitle, currentMode: value, currentModeName: name, subTitle, }); // 更新绘制服务的 title 和 subTitle if (this.drawService) { this.drawService.options.title = pageTitle; this.drawService.options.subTitle = subTitle; } // 重新生成数据 this.onRandom(); }, });