/** * 数字排序绘制服务 */ import { BaseDrawService } from '../../../core/draw/baseDraw'; /** * 数字排序数据 */ export interface NumberSortData { /** 6组题目数据 */ groups: Array<{ /** 4个乱序的数字及其颜色 */ numbers: Array<{ number: number; color: string; angle?: number; // 倾斜角度(弧度),-30度到+30度 }>; }>; } /** * 数字排序绘制服务 */ class NumberSortDraw extends BaseDrawService { sortData: NumberSortData | null = null; constructor( canvas: Canvas, ctx: RenderingContext, options?: Record, ) { super(canvas, ctx, options); } /** * 绘制数字排序内容 */ async draw(sortData: NumberSortData) { if (!sortData || !sortData.groups) { return; } this.sortData = sortData; this.prepareDraw(); await this.drawHeaderAndDivider(); this.drawContent({ ctx: this.ctx, sortData: this.sortData, canvasWidth: this.canvasWidth, startY: this.currentY, }); } /** * 绘制内容区域 */ private drawContent(params: { ctx: RenderingContext; sortData: NumberSortData; canvasWidth: number; startY: number; }): void { const { ctx, sortData, canvasWidth } = params; let { startY } = params; startY = startY + 25; const margin = 40; // 左右边距 const rowSpacing = 60; // 行间距 const colSpacing = 40; // 列间距 const boxSpacing = 10; // 格子之间的间距 // 数字区域参数 const numberSize = 120; // 数字大小(字体大小) const numberAreaHeight = 120; // 数字区域高度(增大以容纳更大的数字) const numberOverlapSpacing = 35; // 数字之间的间距(用于重叠效果) // 格子参数 const boxWidth = 40; // 格子宽度 const boxHeight = 50; // 格子高度(高比宽长) const boxBorderWidth = 1; // 边框宽度 const boxBorderColor = '#999'; // 边框颜色 // 4个格子的总宽度 const boxesTotalWidth = 4 * boxWidth + 3 * boxSpacing; // 每组的总宽度(以格子的总宽度为准) const groupWidth = boxesTotalWidth; // 计算总宽度(两列 + 一列间距) const totalWidth = 2 * groupWidth + colSpacing; const groupsStartX = margin + (canvasWidth - margin * 2 - totalWidth) / 2; // 每组的总高度(数字区域 + 格子区域) const groupHeight = numberAreaHeight + boxHeight; // 绘制6个组(三行两列) for (let row = 0; row < 3; row++) { for (let col = 0; col < 2; col++) { const groupIndex = row * 2 + col; const group = sortData.groups[groupIndex]; if (!group) continue; const groupX = groupsStartX + col * (groupWidth + colSpacing); const groupY = startY + row * (groupHeight + rowSpacing); // 格子的起始X坐标(居中) const boxesStartX = groupX; const boxesY = groupY + numberAreaHeight; // 计算数字组的中心位置(与格子中心对齐) const boxesCenterX = boxesStartX + boxesTotalWidth / 2; // 计算数字组的总宽度(从第一个数字中心到最后一个数字中心的距离) const numbersGroupWidth = 3 * numberOverlapSpacing; // 第一个数字的中心位置(数字组居中对齐) const firstNumberCenterX = boxesCenterX - numbersGroupWidth / 2; // 绘制4个数字(上边),有重叠效果 for (let i = 0; i < group.numbers.length; i++) { const numberItem = group.numbers[i]; // 数字中心位置(有重叠) const numberX = firstNumberCenterX + i * numberOverlapSpacing; const numberY = groupY + numberAreaHeight / 2; // 获取倾斜角度(如果存在,否则使用0) const angle = numberItem.angle || 0; // 保存上下文状态 ctx.save(); // 移动到数字位置 ctx.translate(numberX, numberY); // 旋转(角度转换为弧度) ctx.rotate(angle); // 绘制数字(带边线) const text = numberItem.number.toString(); ctx.font = `bold ${numberSize}px Arial`; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; // 先绘制边线 ctx.strokeStyle = '#141414'; ctx.lineWidth = 3; ctx.strokeText(text, 0, 0); // 再绘制填充 ctx.fillStyle = numberItem.color; ctx.fillText(text, 0, 0); // 恢复上下文状态 ctx.restore(); } // 绘制4个长方形格子(下边) for (let i = 0; i < 4; i++) { const boxX = boxesStartX + i * (boxWidth + boxSpacing); // 绘制格子边框 ctx.strokeStyle = boxBorderColor; ctx.lineWidth = boxBorderWidth; ctx.beginPath(); ctx.rect(boxX, boxesY, boxWidth, boxHeight); ctx.stroke(); } } } } } export default NumberSortDraw;