/** * 格子仿画绘制服务 * 合并了基础绘制和内容绘制逻辑 */ import { BaseDrawService } from '../../../service/baseDraw'; import { GridCell, GridConfig } from '../types/gridTypes'; /** * 格子组数据(一组包含一个填充的网格和一个空的网格) */ export interface GridGroup { /** 填充的格子数据 */ filledCells: GridCell[]; /** 空的格子(用于仿画) */ emptyCells: GridCell[]; // 始终为空数组,仅用于标识 } /** * 格子仿画数据 */ export interface GridDrawingData { config: GridConfig; /** 格子组数组,每组包含一个填充的网格和一个空的网格 */ groups: GridGroup[]; /** 每行展示的组数 */ groupsPerRow: number; /** 总行数 */ totalRows: number; } /** * 格子仿画绘制服务 */ class GridDraw extends BaseDrawService { gridData: GridDrawingData | null = null; constructor( canvas: Canvas, ctx: RenderingContext, options?: Record, ) { super(canvas, ctx, options); } /** * 绘制格子仿画内容 */ async draw(gridData: GridDrawingData) { if (!gridData || !gridData.groups || gridData.groups.length === 0) { return; } this.setPrintConfig(); this.gridData = gridData; this.clear(); this.setPaper(); // 绘制Header if (this.headerType !== 'minimal') { await this.drawHeader(); } else { this.drawMiniHeader(); } // 绘制内容区域(网格和填充) this.drawDivider(); await this.drawGridContent({ canvas: this.canvas, ctx: this.ctx, gridData: this.gridData, canvasWidth: this.canvasWidth, startY: this.currentY, }); } /** * 绘制网格内容 */ private async drawGridContent(params: { canvas: WechatMiniprogram.Canvas; ctx: RenderingContext; gridData: GridDrawingData; canvasWidth: number; startY: number; }): Promise { const { ctx, gridData, canvasWidth, startY } = params; const { config, groups, groupsPerRow, totalRows } = gridData; const { rows, cols } = config; // 计算网格尺寸 const margin = 40; // 左右边距 const groupSpacing = 20; // 组之间的间距 const rowSpacing = 30; // 行之间的间距 const dividerWidth = 2; // 分割线宽度 // 计算每组网格的尺寸 const availableWidth = canvasWidth - margin * 2; const totalGroupsPerRow = groupsPerRow * 2; // 每组包含填充和空两个网格 const groupWidth = (availableWidth - (groupsPerRow - 1) * dividerWidth - (totalGroupsPerRow - 1) * groupSpacing) / totalGroupsPerRow; const cellSize = Math.floor(groupWidth / cols); const gridWidth = cellSize * cols; const gridHeight = cellSize * rows; let currentY = startY + 30; // 顶部间距 // 遍历每一行 for (let rowIndex = 0; rowIndex < totalRows; rowIndex++) { const rowStartIndex = rowIndex * groupsPerRow; const rowGroups = groups.slice( rowStartIndex, rowStartIndex + groupsPerRow, ); // 计算当前行的起始X位置(居中) const rowTotalWidth = totalGroupsPerRow * gridWidth + (totalGroupsPerRow - 1) * groupSpacing + (groupsPerRow - 1) * dividerWidth; const rowStartX = margin + (availableWidth - rowTotalWidth) / 2; let currentX = rowStartX; // 遍历当前行的每一组 for ( let groupIndex = 0; groupIndex < rowGroups.length; groupIndex++ ) { const group = rowGroups[groupIndex]; // 绘制填充的网格(左侧) this.drawSingleGrid({ ctx, gridStartX: currentX, gridStartY: currentY, gridWidth, gridHeight, cellSize, rows, cols, cells: group.filledCells, config, }); currentX += gridWidth + groupSpacing; // 绘制空的网格(右侧) this.drawSingleGrid({ ctx, gridStartX: currentX, gridStartY: currentY, gridWidth, gridHeight, cellSize, rows, cols, cells: [], // 空网格 config, }); currentX += gridWidth; // 如果不是最后一组,绘制垂直分割线 if (groupIndex < rowGroups.length - 1) { ctx.strokeStyle = '#000000'; ctx.lineWidth = dividerWidth; ctx.beginPath(); ctx.moveTo(currentX, currentY); ctx.lineTo(currentX, currentY + gridHeight); ctx.stroke(); currentX += dividerWidth; } } currentY += gridHeight + rowSpacing; // 如果不是最后一行,绘制水平分割线 if (rowIndex < totalRows - 1) { ctx.strokeStyle = '#000000'; ctx.lineWidth = dividerWidth; ctx.beginPath(); ctx.moveTo(margin, currentY - rowSpacing / 2); ctx.lineTo(canvasWidth - margin, currentY - rowSpacing / 2); ctx.stroke(); } } } /** * 绘制单个网格 */ private drawSingleGrid(params: { ctx: RenderingContext; gridStartX: number; gridStartY: number; gridWidth: number; gridHeight: number; cellSize: number; rows: number; cols: number; cells: GridCell[]; config: GridConfig; }): void { const { ctx, gridStartX, gridStartY, gridWidth, gridHeight, cellSize, rows, cols, cells, config, } = params; // 绘制网格线 ctx.strokeStyle = config.gridLineColor || '#000000'; ctx.lineWidth = config.gridLineWidth || 1; ctx.setLineDash([]); // 实线 // 绘制垂直线 for (let i = 0; i <= cols; i++) { const x = gridStartX + i * cellSize; ctx.beginPath(); ctx.moveTo(x, gridStartY); ctx.lineTo(x, gridStartY + gridHeight); ctx.stroke(); } // 绘制水平线 for (let i = 0; i <= rows; i++) { const y = gridStartY + i * cellSize; ctx.beginPath(); ctx.moveTo(gridStartX, y); ctx.lineTo(gridStartX + gridWidth, y); ctx.stroke(); } // 绘制填充的格子 for (const cell of cells) { if (cell.x >= 0 && cell.x < cols && cell.y >= 0 && cell.y < rows) { const x = gridStartX + cell.x * cellSize; const y = gridStartY + cell.y * cellSize; // 填充颜色 ctx.fillStyle = cell.color; ctx.fillRect(x + 1, y + 1, cellSize - 2, cellSize - 2); } } } } export default GridDraw;