Files
2026-04-09 17:43:22 +08:00

211 lines
6.9 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 译码连线绘制服务
*/
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<string, any>,
) {
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<void> {
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;