feat:2.6.1增加 数物对应 和 根据颜色画图形
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* 根据颜色画图形绘制服务
|
||||
*/
|
||||
|
||||
import { BaseDrawService } from '../../../service/baseDraw';
|
||||
import { drawShapeSymbolShape } from '../shapes/shapeSymbolShapes';
|
||||
|
||||
/**
|
||||
* 根据颜色画图形数据
|
||||
*/
|
||||
export interface ColorShapeMatchData {
|
||||
/** 阅览区域的4组数据 */
|
||||
legendItems: Array<{
|
||||
shapeId: string;
|
||||
color: string;
|
||||
}>;
|
||||
/** 练习区域的5x5网格数据 */
|
||||
practiceGrid: Array<Array<string | null>>; // 存储颜色,null表示空白
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据颜色画图形绘制服务
|
||||
*/
|
||||
class ColorShapeMatchDraw extends BaseDrawService {
|
||||
gridData: ColorShapeMatchData | null = null;
|
||||
|
||||
constructor(
|
||||
canvas: Canvas,
|
||||
ctx: RenderingContext,
|
||||
options?: Record<string, any>,
|
||||
) {
|
||||
super(canvas, ctx, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制根据颜色画图形内容
|
||||
*/
|
||||
async draw(gridData: ColorShapeMatchData) {
|
||||
if (!gridData || !gridData.legendItems || !gridData.practiceGrid) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.gridData = gridData;
|
||||
this.prepareDraw();
|
||||
await this.drawHeaderAndDivider();
|
||||
this.drawContent({
|
||||
ctx: this.ctx,
|
||||
gridData: this.gridData,
|
||||
canvasWidth: this.canvasWidth,
|
||||
startY: this.currentY,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制内容区域
|
||||
*/
|
||||
private drawContent(params: {
|
||||
ctx: RenderingContext;
|
||||
gridData: ColorShapeMatchData;
|
||||
canvasWidth: number;
|
||||
startY: number;
|
||||
}): void {
|
||||
const { ctx, gridData, canvasWidth } = params;
|
||||
let { startY } = params;
|
||||
|
||||
startY = startY + 25;
|
||||
|
||||
const margin = 40; // 左右边距
|
||||
const groupSpacing = 40; // 组间距
|
||||
const groupSize = 80; // 每组的大小(图形外框大小)
|
||||
const dotRadius = 15; // 中间圆点的半径
|
||||
|
||||
// 计算阅览区域的总宽度
|
||||
const totalWidth = groupSize * 4 + groupSpacing * 3; // 4组 + 3个间距
|
||||
const legendStartX =
|
||||
margin + (canvasWidth - margin * 2 - totalWidth) / 2; // 居中
|
||||
const legendStartY = startY;
|
||||
|
||||
// 绘制阅览区域的4组
|
||||
gridData.legendItems.forEach((item, index) => {
|
||||
const groupX = legendStartX + index * (groupSize + groupSpacing);
|
||||
const groupY = legendStartY;
|
||||
const centerX = groupX + groupSize / 2;
|
||||
const centerY = groupY + groupSize / 2;
|
||||
|
||||
// 绘制外部图形(有边框,无填充)
|
||||
drawShapeSymbolShape(
|
||||
ctx,
|
||||
item.shapeId,
|
||||
centerX,
|
||||
centerY,
|
||||
groupSize * 1.1, // 图形大小略小于外框
|
||||
{
|
||||
fillColor: null,
|
||||
strokeColor: '#000',
|
||||
strokeWidth: 2,
|
||||
},
|
||||
);
|
||||
|
||||
// 绘制中间的圆点(无边线,有填充)
|
||||
ctx.beginPath();
|
||||
ctx.arc(centerX, centerY, dotRadius, 0, Math.PI * 2);
|
||||
ctx.fillStyle = item.color;
|
||||
ctx.fill();
|
||||
});
|
||||
|
||||
// 绘制虚线分割线
|
||||
const dividerY = legendStartY + groupSize + 30;
|
||||
this.drawDashedDivider(dividerY, margin);
|
||||
|
||||
// 绘制练习区域(5行5列)
|
||||
const practiceStartY = dividerY + 30;
|
||||
const practiceCols = 5;
|
||||
const practiceRows = 5;
|
||||
const practiceCellSize = 100; // 每个格子的宽度
|
||||
const practiceGridWidth = practiceCellSize * practiceCols;
|
||||
|
||||
// 计算练习区域起始X位置(居中)
|
||||
const practiceStartX =
|
||||
margin + (canvasWidth - margin * 2 - practiceGridWidth) / 2;
|
||||
|
||||
// // 绘制练习区域网格线
|
||||
// this.drawGridLines(
|
||||
// practiceStartX,
|
||||
// practiceStartY,
|
||||
// practiceCellSize,
|
||||
// practiceCellSize,
|
||||
// practiceCols,
|
||||
// practiceRows,
|
||||
// );
|
||||
|
||||
// 绘制练习区域的圆点
|
||||
// const dotRadius = 15; // 圆点半径
|
||||
for (let row = 0; row < practiceRows; row++) {
|
||||
const practiceRow = gridData.practiceGrid[row];
|
||||
if (!practiceRow) continue;
|
||||
|
||||
const rowY = practiceStartY + row * practiceCellSize;
|
||||
const cellCenterY = rowY + practiceCellSize / 2;
|
||||
|
||||
for (let col = 0; col < practiceCols; col++) {
|
||||
const color = practiceRow[col];
|
||||
if (!color) continue;
|
||||
|
||||
const colX = practiceStartX + col * practiceCellSize;
|
||||
const cellCenterX = colX + practiceCellSize / 2;
|
||||
|
||||
// 绘制圆点(无边线,有填充)
|
||||
ctx.beginPath();
|
||||
ctx.arc(cellCenterX, cellCenterY, dotRadius, 0, Math.PI * 2);
|
||||
ctx.fillStyle = color;
|
||||
ctx.fill();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default ColorShapeMatchDraw;
|
||||
@@ -145,12 +145,13 @@ export function drawShapeSymbolShape(
|
||||
break;
|
||||
|
||||
case 'triangle':
|
||||
// 三角形缩小为原来的0.9倍
|
||||
const triangleRadius = radius * 0.9;
|
||||
// 三角形缩小为原来的0.9倍,整体中心提高
|
||||
// const triangleRadius = radius * 0.9;
|
||||
const bottomY = radius * 0.7; // 减少底部Y坐标,使整体中心提高
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, -triangleRadius);
|
||||
ctx.lineTo(-triangleRadius, triangleRadius);
|
||||
ctx.lineTo(triangleRadius, triangleRadius);
|
||||
ctx.moveTo(0, -radius);
|
||||
ctx.lineTo(-radius, bottomY);
|
||||
ctx.lineTo(radius, bottomY);
|
||||
ctx.closePath();
|
||||
drawPath();
|
||||
break;
|
||||
@@ -176,9 +177,10 @@ export function drawShapeSymbolShape(
|
||||
drawPath();
|
||||
break;
|
||||
|
||||
// 椭圆
|
||||
case 'ellipse':
|
||||
ctx.beginPath();
|
||||
ctx.ellipse(0, 0, radius * 0.8, radius * 0.6, 0, 0, Math.PI * 2);
|
||||
ctx.ellipse(0, 0, radius, radius * 0.8, 0, 0, Math.PI * 2);
|
||||
drawPath();
|
||||
break;
|
||||
|
||||
@@ -287,17 +289,21 @@ export function drawShapeSymbolShape(
|
||||
|
||||
// 扇形
|
||||
case 'sector':
|
||||
// 扇形(90度扇形),圆心在格子中心点偏左二分之一的位置
|
||||
const sectorCenterX = -radius / 2; // 向左偏移半径的一半
|
||||
const sectorCenterY = 0;
|
||||
const sectorRadius = radius * 1.5;
|
||||
// 扇形(圆弧在正上方,圆点在正下方)
|
||||
const sectorCenterX = 0; // 圆心在水平中心
|
||||
const sectorCenterY = sectorRadius * 0.55; // 圆心在正下方
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(sectorCenterX, sectorCenterY);
|
||||
// 从左侧上方到右侧上方绘制圆弧(135度到225度)
|
||||
ctx.arc(
|
||||
sectorCenterX,
|
||||
sectorCenterY,
|
||||
radius,
|
||||
sectorRadius,
|
||||
(-3 * Math.PI) / 4,
|
||||
-Math.PI / 4,
|
||||
Math.PI / 4,
|
||||
// (Math.PI * 3) / 4, // 左侧上方(135度)
|
||||
// (Math.PI * 5) / 4, // 右侧上方(225度)
|
||||
false,
|
||||
);
|
||||
ctx.lineTo(sectorCenterX, sectorCenterY);
|
||||
|
||||
Reference in New Issue
Block a user