/** * 译码连线绘制服务 */ import { BaseDrawService } from '../../../core/draw/baseDraw'; /** * 译码连线数据 */ export interface CodeConnectData { /** 参考区域:数字到颜色的映射(8个数字,可能是1-8、2-9、3-10) */ colorMap: Array<{ number: number; // 数字(可能是1-8、2-9、3-10) color: string; }>; /** 起始数字(1、2或3) */ startNumber: number; /** 内容区域:4个组的题目 */ groups: Array<{ /** 数字序列(6个数字,用-连接) */ sequence: number[]; /** 圆环内圆点的位置和颜色(8个圆点,圆形分布) */ dots: Array<{ number: number; // 对应的数字 color: string; // 对应的颜色 angle: number; // 角度(弧度) }>; }>; } /** * 译码连线绘制服务 */ class CodeConnectDraw extends BaseDrawService { codeData: CodeConnectData | null = null; constructor( canvas: Canvas, ctx: RenderingContext, options?: Record, ) { super(canvas, ctx, options); } /** * 绘制译码连线内容 */ async draw(codeData: CodeConnectData) { if (!codeData || !codeData.colorMap || !codeData.groups) { return; } this.codeData = codeData; this.prepareDraw(); await this.drawHeaderAndDivider(); await this.drawContent({ canvas: this.canvas, ctx: this.ctx, codeData: this.codeData, canvasWidth: this.canvasWidth, startY: this.currentY, }); } /** * 绘制内容区域 */ private async drawContent(params: { canvas: WechatMiniprogram.Canvas; ctx: RenderingContext; codeData: CodeConnectData; canvasWidth: number; startY: number; }): Promise { const { ctx, codeData, canvasWidth } = params; let { startY } = params; startY = startY + 25; const margin = 40; // 左右边距 // ========== 上部参考区域 ========== const referenceStartY = startY; const referenceCellSize = 50; // 每个方格的大小 const referenceGridWidth = referenceCellSize * 8; // 网格总宽度(8列) // 计算参考区域的起始X坐标(居中) const referenceStartX = margin + (canvasWidth - margin * 2 - referenceGridWidth) / 2; // 使用drawGridLines绘制网格(2行8列,格子之间没有间距) this.drawGridLines( referenceStartX, referenceStartY, referenceCellSize, referenceCellSize, 8, 2, ); // 绘制第一行:数字 for (let i = 0; i < 8; i++) { const cellX = referenceStartX + i * referenceCellSize; const cellY = referenceStartY; // 绘制数字 const number = codeData.colorMap[i].number; ctx.fillStyle = '#000'; ctx.font = 'bold 24px Arial'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText( number.toString(), cellX + referenceCellSize / 2, cellY + referenceCellSize / 2, ); } // 绘制第二行:圆点 const dotRowY = referenceStartY + referenceCellSize; const dotRadius = 15; // 圆点半径 for (let i = 0; i < 8; i++) { const cellX = referenceStartX + i * referenceCellSize; const cellY = dotRowY; // 绘制圆点(有边框) const dotX = cellX + referenceCellSize / 2; const dotY = cellY + referenceCellSize / 2; const color = codeData.colorMap[i].color; this.drawDot(ctx, dotX, dotY, dotRadius, color, '#000'); } // ========== 虚线分割 ========== const dividerY = dotRowY + referenceCellSize + 30; this.drawDashedDivider(dividerY, margin); // ========== 下部内容区域 ========== const contentStartY = dividerY + 40; const groupSpacingX = 80; // 一行中两组之间的间距 const groupSpacingY = 45; // 行之间的间距 const textCircleSpacing = 15; // 数字文本与圆环的间距 const circleRadius = 90; // 大圆环半径 const dotPadding = 10; // 圆点距离圆环边线的间距 const innerRadius = circleRadius - dotPadding - dotRadius; // 圆点分布圆的半径 const textHeight = 25; // 数字文本的高度 // 计算每组的总宽度(包括圆环) const groupWidth = circleRadius * 2; const totalGroupsWidth = 2 * groupWidth + groupSpacingX; const groupsStartX = margin + (canvasWidth - margin * 2 - totalGroupsWidth) / 2; // 绘制4个组(两行两列) for (let row = 0; row < 2; row++) { for (let col = 0; col < 2; col++) { const groupIndex = row * 2 + col; const group = codeData.groups[groupIndex]; if (!group) continue; const groupX = groupsStartX + col * (groupWidth + groupSpacingX); const groupY = contentStartY + row * (circleRadius * 2 + textHeight + groupSpacingY + textCircleSpacing); // 绘制大圆环 const circleCenterX = groupX + groupWidth / 2; const circleCenterY = groupY + textHeight + circleRadius + textCircleSpacing; ctx.strokeStyle = '#888'; ctx.lineWidth = 1; ctx.beginPath(); ctx.arc( circleCenterX, circleCenterY, circleRadius, 0, Math.PI * 2, ); ctx.stroke(); // 绘制数字序列(在圆环正上方) const sequenceText = group.sequence.join('-'); ctx.fillStyle = '#000'; ctx.font = 'bold 20px Arial'; ctx.textAlign = 'center'; ctx.textBaseline = 'bottom'; ctx.fillText(sequenceText, circleCenterX, groupY + textHeight); // 绘制圆环内的8个圆点(圆形分布) for (const dot of group.dots) { const dotX = circleCenterX + Math.cos(dot.angle) * innerRadius; const dotY = circleCenterY + Math.sin(dot.angle) * innerRadius; // 绘制圆点(有边框) this.drawDot(ctx, dotX, dotY, dotRadius, dot.color, '#000'); } } } } } export default CodeConnectDraw;