/** * 填上缺少的数字绘制服务 */ import { BaseDrawService } from '../../../core/draw/baseDraw'; /** * 填上缺少的数字数据 */ export interface MissingNumberData { grids: Array<{ numbers: (number | null)[]; colors: (string | null)[]; }>; maxNumber: number; } /** * 填上缺少的数字绘制服务 */ class MissingNumberDraw extends BaseDrawService { missingNumberData: MissingNumberData | null = null; constructor( canvas: Canvas, ctx: RenderingContext, options?: Record, ) { super(canvas, ctx, options); this.missingNumberData = null; } /** * 绘制填上缺少的数字内容 */ async draw( missingNumberData: MissingNumberData, rangeType: string = 'within-10', ) { if (!missingNumberData || !missingNumberData.grids) { return; } this.missingNumberData = missingNumberData; this.prepareDraw(); await this.drawHeaderAndDivider(); await this.drawContent({ canvas: this.canvas, ctx: this.ctx, missingNumberData: this.missingNumberData, canvasWidth: this.canvasWidth, startY: this.currentY, }); } /** * 绘制内容区域 */ private async drawContent(params: { canvas: WechatMiniprogram.Canvas; ctx: RenderingContext; missingNumberData: MissingNumberData; canvasWidth: number; startY: number; }): Promise { const { ctx, missingNumberData, canvasWidth, startY } = params; const { grids, maxNumber } = missingNumberData; const gridMap = { 10: { cellSize: 95, colsPerGrid: 5, fontSize: 50, gridSpacing: 40, }, 20: { cellSize: 80, colsPerGrid: 5, fontSize: 40, gridSpacing: 30, }, 40: { cellSize: 60, colsPerGrid: 8, fontSize: 35, gridSpacing: 30, }, 50: { cellSize: 52, colsPerGrid: 10, fontSize: 28, gridSpacing: 40, }, 80: { cellSize: 60, colsPerGrid: 8, fontSize: 30, gridSpacing: 30, }, 100: { cellSize: 52, colsPerGrid: 10, fontSize: 28, gridSpacing: 20, }, 120: { cellSize: 52, colsPerGrid: 10, fontSize: 28, gridSpacing: 20, }, }; // 计算网格布局参数 const leftMargin = 40; const rightMargin = 40; const topMargin = 20; const config = gridMap[maxNumber as keyof typeof gridMap]; const { cellSize, gridSpacing, colsPerGrid, fontSize } = config; const gridWidth = colsPerGrid * cellSize; // 计算网格的起始X位置(居中) const gridStartX = leftMargin + (canvasWidth - leftMargin - rightMargin - gridWidth) / 2; let currentY = startY + topMargin; // 绘制每个网格 for (let gridIndex = 0; gridIndex < grids.length; gridIndex++) { const grid = grids[gridIndex]; const gridX = gridStartX; // 根据实际数字数量计算需要的行数 const rowsPerGrid = Math.ceil(grid.numbers.length / colsPerGrid); const gridHeight = rowsPerGrid * cellSize; const gridY = currentY; // 绘制每个单元格 for (let index = 0; index < grid.numbers.length; index++) { const row = Math.floor(index / colsPerGrid); const col = index % colsPerGrid; const cellX = gridX + col * cellSize; const cellY = gridY + row * cellSize; // 绘制单元格边框 ctx.strokeStyle = '#333'; ctx.lineWidth = 1.5; ctx.strokeRect(cellX, cellY, cellSize, cellSize); // 绘制数字或空白 const number = grid.numbers[index]; const color = grid.colors[index]; if (number !== null && color !== null) { // 绘制数字(带颜色) ctx.fillStyle = color; ctx.font = `bold ${fontSize}px "Microsoft Yahei"`; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText( String(number), cellX + cellSize / 2, cellY + cellSize / 2, ); } // 如果为null,则留空(用户填写) } // 更新下一个网格的Y位置 currentY += gridHeight + gridSpacing; } } } export default MissingNumberDraw;