/** * 数字点连线绘制服务 */ import { BaseDrawService } from '../../../service/baseDraw'; /** * 数字点连线数据 */ export interface DotConnectData { /** 参考区域:数字到颜色的映射(1-9) */ colorMap: Array<{ number: number; // 数字(1-9) color: string; }>; /** 内容区域:9个组的题目 */ groups: Array<{ /** 数字序列 */ sequence: number[]; }>; } /** * 数字点连线绘制服务 */ class DotConnectDraw extends BaseDrawService { dotConnectData: DotConnectData | null = null; constructor( canvas: Canvas, ctx: RenderingContext, options?: Record, ) { super(canvas, ctx, options); } /** * 绘制数字点连线内容 */ async draw(dotConnectData: DotConnectData) { if ( !dotConnectData || !dotConnectData.colorMap || !dotConnectData.groups ) { return; } this.dotConnectData = dotConnectData; this.prepareDraw(); await this.drawHeaderAndDivider(); await this.drawContent({ canvas: this.canvas, ctx: this.ctx, dotConnectData: this.dotConnectData, canvasWidth: this.canvasWidth, startY: this.currentY, }); } /** * 绘制内容区域 */ private async drawContent(params: { canvas: WechatMiniprogram.Canvas; ctx: RenderingContext; dotConnectData: DotConnectData; canvasWidth: number; startY: number; }): Promise { const { ctx, dotConnectData, canvasWidth } = params; let { startY } = params; startY = startY + 25; const margin = 40; // 左右边距 // ========== 上部参考区域:3x3 九宫格 ========== const referenceStartY = startY; const referenceCellSize = 38; // 每个方格的大小 const referenceGridWidth = referenceCellSize * 3; // 网格总宽度(3列) const referenceGridHeight = referenceCellSize * 3; // 网格总高度(3行) // 计算参考区域的起始X坐标(居中) const referenceStartX = margin + (canvasWidth - margin * 2 - referenceGridWidth) / 2; // 使用drawGridLines绘制网格(3行3列) this.drawGridLines( referenceStartX, referenceStartY, referenceCellSize, referenceCellSize, 3, 3, ); // 绘制数字(1-9),每个数字使用对应的颜色 for (let row = 0; row < 3; row++) { for (let col = 0; col < 3; col++) { const number = row * 3 + col + 1; // 1-9 const cellX = referenceStartX + col * referenceCellSize; const cellY = referenceStartY + row * referenceCellSize; // 查找数字对应的颜色 const colorInfo = dotConnectData.colorMap.find( (m) => m.number === number, ); const color = colorInfo?.color || '#000'; // 绘制数字(使用对应颜色) ctx.fillStyle = color; ctx.font = 'bold 24px Arial'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText( number.toString(), cellX + referenceCellSize / 2, cellY + referenceCellSize / 2, ); } } // ========== 虚线分割 ========== const dividerY = referenceStartY + referenceGridHeight + 20; this.drawDashedDivider(dividerY, margin); // ========== 下部内容区域:9个组 ========== const contentStartY = dividerY + 20; const dotSpacing = 35; // 圆点间距 const dotRadius = 6; // 圆点半径 const boxPadding = 20; // 框内边距 const boxWidth = dotSpacing * 2 + boxPadding * 2; // 框的宽度(3个圆点,2个间距) const boxHeight = boxWidth; // 框的高度(正方形) const textHeight = 25; // 数字文本的高度 const textBoxSpacing = 12; // 数字文本与框的间距 const groupSpacingX = 60; // 一行中两组之间的间距 const groupSpacingY = 30; // 行之间的间距 // 计算每组的总宽度和高度 const groupWidth = boxWidth; const groupHeight = textHeight + textBoxSpacing + boxHeight; const totalGroupsWidth = 3 * groupWidth + 2 * groupSpacingX; const groupsStartX = margin + (canvasWidth - margin * 2 - totalGroupsWidth) / 2; // 绘制9个组(三行三列) for (let row = 0; row < 3; row++) { for (let col = 0; col < 3; col++) { const groupIndex = row * 3 + col; const group = dotConnectData.groups[groupIndex]; if (!group) continue; const groupX = groupsStartX + col * (groupWidth + groupSpacingX); const groupY = contentStartY + row * (groupHeight + groupSpacingY); // 绘制数字序列(在框正上方,居中) const sequenceText = group.sequence.join('-'); ctx.fillStyle = '#000'; ctx.font = '18px Arial'; ctx.textAlign = 'center'; ctx.textBaseline = 'bottom'; const textX = groupX + groupWidth / 2; const textY = groupY + textHeight; ctx.fillText(sequenceText, textX, textY); // 绘制虚线圆角框 const boxX = groupX; const boxY = groupY + textHeight + textBoxSpacing; this.drawRoundedRect(boxX, boxY, boxWidth, boxHeight, { isDashed: true, color: '#999', lineWidth: 1, radius: 10, }); // 计算框内圆点的起始位置(居中) const dotsStartX = boxX + boxPadding; const dotsStartY = boxY + boxPadding; // 绘制3x3圆点网格 for (let dotRow = 0; dotRow < 3; dotRow++) { for (let dotCol = 0; dotCol < 3; dotCol++) { const dotNumber = dotRow * 3 + dotCol + 1; // 1-9 const dotX = dotsStartX + dotCol * dotSpacing; const dotY = dotsStartY + dotRow * dotSpacing; // 查找数字对应的颜色 const colorInfo = dotConnectData.colorMap.find( (m) => m.number === dotNumber, ); const dotColor = colorInfo?.color || '#000'; // 绘制圆点(黑色边框) this.drawDot( ctx, dotX, dotY, dotRadius, dotColor, '#000', ); } } } } } } export default DotConnectDraw;