feat:2.6.2 凑十法
This commit is contained in:
@@ -19,7 +19,8 @@
|
|||||||
"countingSelect/countingSelect",
|
"countingSelect/countingSelect",
|
||||||
"numberDecompose/numberDecompose",
|
"numberDecompose/numberDecompose",
|
||||||
"numberSort/numberSort",
|
"numberSort/numberSort",
|
||||||
"numberObjectMatch/numberObjectMatch"
|
"numberObjectMatch/numberObjectMatch",
|
||||||
|
"makeTen/makeTen"
|
||||||
],
|
],
|
||||||
"independent": false
|
"independent": false
|
||||||
},
|
},
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
@@ -149,4 +149,12 @@ export const MATH_FUNCTION_TYPES: MathFunctionType[] = [
|
|||||||
icon: '🔢',
|
icon: '🔢',
|
||||||
img: '/assets/mathEntrance/number-decompose-20.png',
|
img: '/assets/mathEntrance/number-decompose-20.png',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'make-ten',
|
||||||
|
page: 'makeTen',
|
||||||
|
title: '凑十法练习',
|
||||||
|
desc: '通过凑十法学习20以内进位加法',
|
||||||
|
icon: '➕',
|
||||||
|
img: '/assets/mathEntrance/make-ten.png',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"navigationBarTitleText": "凑十法练习",
|
||||||
|
"navigationBarBackgroundColor": "#FFD719",
|
||||||
|
"homeButton": true,
|
||||||
|
"backgroundColor": "#F6F6F6",
|
||||||
|
"enablePullDownRefresh": false,
|
||||||
|
"usingComponents": {
|
||||||
|
"toy-button": "../../ui/button/button",
|
||||||
|
"share-guide-popup": "../../components/share-guide-popup/share-guide-popup",
|
||||||
|
"math-bottom-buttons": "../../components/math-bottom-buttons/math-bottom-buttons",
|
||||||
|
"draw-ad": "../../components/draw-ad/draw-ad"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
// 凑十法练习页面样式
|
||||||
|
|
||||||
|
@import '../../base/baseDrawPage.wxss';
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
import MakeTenDraw from '../shared/service/makeTenDraw';
|
||||||
|
import {
|
||||||
|
createMathPage,
|
||||||
|
CanvasDataState,
|
||||||
|
} from '../shared/common/mathPageMixin';
|
||||||
|
|
||||||
|
createMathPage({
|
||||||
|
canvas: null as Canvas | null,
|
||||||
|
ctx: null as RenderingContext | null,
|
||||||
|
boxHeight: 0,
|
||||||
|
boxWidth: 0,
|
||||||
|
drawService: null as MakeTenDraw | null,
|
||||||
|
makeTenData: null as {
|
||||||
|
problems: Array<{
|
||||||
|
left: number;
|
||||||
|
right: number;
|
||||||
|
result: number;
|
||||||
|
}>;
|
||||||
|
} | null,
|
||||||
|
|
||||||
|
data: {
|
||||||
|
pageTitle: '凑十法练习',
|
||||||
|
subTitle: '通过凑十法学习20以内进位加法',
|
||||||
|
functionId: '',
|
||||||
|
hasContent: false,
|
||||||
|
showShareDialog: false,
|
||||||
|
} as CanvasDataState,
|
||||||
|
|
||||||
|
onLoad(options: { id?: string }) {
|
||||||
|
const functionId = options.id || 'make-ten';
|
||||||
|
this.initPageInfo(functionId, '凑十法练习');
|
||||||
|
},
|
||||||
|
|
||||||
|
onReady() {
|
||||||
|
this.initCanvas({
|
||||||
|
createDrawService: (
|
||||||
|
canvas: Canvas,
|
||||||
|
ctx: RenderingContext,
|
||||||
|
options?: Record<string, any>,
|
||||||
|
) => {
|
||||||
|
return new MakeTenDraw(canvas, ctx, options);
|
||||||
|
},
|
||||||
|
drawServiceOptions: {
|
||||||
|
subTitle: this.data.subTitle,
|
||||||
|
},
|
||||||
|
onCanvasReady: () => {
|
||||||
|
// 初始随机生成
|
||||||
|
this.onRandom();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制Canvas内容
|
||||||
|
*/
|
||||||
|
async drawCanvas() {
|
||||||
|
if (!this.ctx || !this.drawService || !this.makeTenData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.drawService.draw(this.makeTenData);
|
||||||
|
this.setData({ hasContent: true });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('绘制失败:', error);
|
||||||
|
this.setData({ hasContent: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 随机生成
|
||||||
|
*/
|
||||||
|
onRandom() {
|
||||||
|
const problems: Array<{
|
||||||
|
left: number;
|
||||||
|
right: number;
|
||||||
|
result: number;
|
||||||
|
}> = [];
|
||||||
|
// 用于记录已生成的题目,避免重复(9+2 和 2+9 视为不同)
|
||||||
|
const usedProblems = new Set<string>();
|
||||||
|
|
||||||
|
// 生成9道题目(3行3列)
|
||||||
|
let attempts = 0;
|
||||||
|
const maxAttempts = 1000; // 最大尝试次数,避免无限循环
|
||||||
|
|
||||||
|
while (problems.length < 9 && attempts < maxAttempts) {
|
||||||
|
attempts++;
|
||||||
|
// 生成两个数,确保:
|
||||||
|
// 1. 两个加数都在1-9之间(不能是10)
|
||||||
|
// 2. 和大于10且小于等于20(需要凑十法)
|
||||||
|
// 3. 大数至少是6(因为5无法满足条件:5 + 最大小数4 = 9 < 11)
|
||||||
|
let left: number;
|
||||||
|
let right: number;
|
||||||
|
|
||||||
|
// 随机决定大数在前还是在后
|
||||||
|
const bigFirst = Math.random() < 0.5;
|
||||||
|
|
||||||
|
if (bigFirst) {
|
||||||
|
// 大数在前:left 在 6-9 之间,right 在 1-9 之间
|
||||||
|
// 确保 left + right >= 11 且 left + right <= 20
|
||||||
|
left = Math.floor(Math.random() * 4) + 6; // 6-9
|
||||||
|
// right 的最小值:确保 left + right >= 11,即 right >= 11 - left
|
||||||
|
const minRight = Math.max(1, 11 - left);
|
||||||
|
// right 的最大值:确保 left + right <= 20,即 right <= 20 - left,且 right <= 9
|
||||||
|
const maxRight = Math.min(9, 20 - left);
|
||||||
|
// 确保 right < left(因为 left 是大数)
|
||||||
|
const actualMaxRight = Math.min(maxRight, left - 1);
|
||||||
|
// 检查是否有有效的 right 值
|
||||||
|
if (actualMaxRight >= minRight) {
|
||||||
|
right =
|
||||||
|
Math.floor(
|
||||||
|
Math.random() * (actualMaxRight - minRight + 1),
|
||||||
|
) + minRight;
|
||||||
|
} else {
|
||||||
|
// 如果无法生成有效值,跳过本次循环
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 大数在后:left 在 1-9 之间,right 在 6-9 之间
|
||||||
|
// 确保 left + right >= 11 且 left + right <= 20
|
||||||
|
right = Math.floor(Math.random() * 4) + 6; // 6-9
|
||||||
|
// left 的最小值:确保 left + right >= 11,即 left >= 11 - right
|
||||||
|
const minLeft = Math.max(1, 11 - right);
|
||||||
|
// left 的最大值:确保 left + right <= 20,即 left <= 20 - right,且 left <= 9
|
||||||
|
const maxLeft = Math.min(9, 20 - right);
|
||||||
|
// 确保 left < right(因为 right 是大数)
|
||||||
|
const actualMaxLeft = Math.min(maxLeft, right - 1);
|
||||||
|
// 检查是否有有效的 left 值
|
||||||
|
if (actualMaxLeft >= minLeft) {
|
||||||
|
left =
|
||||||
|
Math.floor(
|
||||||
|
Math.random() * (actualMaxLeft - minLeft + 1),
|
||||||
|
) + minLeft;
|
||||||
|
} else {
|
||||||
|
// 如果无法生成有效值,跳过本次循环
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否重复(9+2 和 2+9 视为不同)
|
||||||
|
const problemKey = `${left},${right}`;
|
||||||
|
if (usedProblems.has(problemKey)) {
|
||||||
|
// 如果已存在,跳过本次循环,重新生成
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加到已使用集合
|
||||||
|
usedProblems.add(problemKey);
|
||||||
|
|
||||||
|
const result = left + right;
|
||||||
|
problems.push({
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
result,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果尝试次数过多仍未生成足够的题目,输出警告
|
||||||
|
if (problems.length < 9) {
|
||||||
|
console.warn(
|
||||||
|
`只生成了 ${problems.length} 道题目,可能符合条件的题目组合不足`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.makeTenData = { problems };
|
||||||
|
this.drawCanvas();
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<!-- 模版不能跨包引用 -->
|
||||||
|
<import src="../shared/templates/canvas-page-template.wxml" />
|
||||||
|
|
||||||
|
<template
|
||||||
|
is="canvasPageTemplate"
|
||||||
|
data="{{boxWidth: boxWidth, boxHeight: boxHeight, hasTypeSelector: false, adType: 'mathDraw', disabled: !hasContent, showShareDialog: showShareDialog}}" />
|
||||||
@@ -0,0 +1,372 @@
|
|||||||
|
/**
|
||||||
|
* 凑十法练习绘制服务
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { BaseDrawService } from '../../../service/baseDraw';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 凑十法数据
|
||||||
|
*/
|
||||||
|
export interface MakeTenData {
|
||||||
|
problems: Array<{
|
||||||
|
left: number;
|
||||||
|
right: number;
|
||||||
|
result: number;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 凑十法练习绘制服务
|
||||||
|
*/
|
||||||
|
class MakeTenDraw extends BaseDrawService {
|
||||||
|
makeTenData: MakeTenData | null = null;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
canvas: Canvas,
|
||||||
|
ctx: RenderingContext,
|
||||||
|
options?: Record<string, any>,
|
||||||
|
) {
|
||||||
|
super(canvas, ctx, options);
|
||||||
|
this.makeTenData = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制凑十法练习内容
|
||||||
|
*/
|
||||||
|
async draw(makeTenData: MakeTenData) {
|
||||||
|
if (!makeTenData || !makeTenData.problems) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.makeTenData = makeTenData;
|
||||||
|
this.prepareDraw();
|
||||||
|
await this.drawHeaderAndDivider();
|
||||||
|
|
||||||
|
// 绘制口诀区域
|
||||||
|
this.drawMnemonic();
|
||||||
|
|
||||||
|
// 绘制虚线分割
|
||||||
|
this.drawDashedDivider(this.currentY + 5, 40, '#999', 1);
|
||||||
|
this.currentY += 20;
|
||||||
|
|
||||||
|
// 绘制题目区域(5行4列)
|
||||||
|
this.drawProblems(makeTenData.problems);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制口诀
|
||||||
|
*/
|
||||||
|
private drawMnemonic() {
|
||||||
|
const { ctx, canvasWidth } = this;
|
||||||
|
const mnemonic = '看大数,拆小数,凑成10,加剩数';
|
||||||
|
const fontSize = 28; // 适合小朋友的字体大小
|
||||||
|
|
||||||
|
// 使用适合小朋友的字体
|
||||||
|
ctx.font = `bold ${fontSize}px "YouYuan", "PingFang SC", "Microsoft Yahei", sans-serif`;
|
||||||
|
ctx.fillStyle = '#343434';
|
||||||
|
ctx.textAlign = 'center';
|
||||||
|
ctx.textBaseline = 'middle';
|
||||||
|
|
||||||
|
// 居中绘制口诀
|
||||||
|
const mnemonicY = this.currentY + 30;
|
||||||
|
ctx.fillText(mnemonic, canvasWidth / 2, mnemonicY);
|
||||||
|
|
||||||
|
// 更新当前Y位置
|
||||||
|
this.currentY = mnemonicY + 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制题目区域(3行3列)
|
||||||
|
*/
|
||||||
|
private drawProblems(
|
||||||
|
problems: Array<{ left: number; right: number; result: number }>,
|
||||||
|
) {
|
||||||
|
const { ctx, canvasWidth } = this;
|
||||||
|
const rows = 3;
|
||||||
|
const cols = 3;
|
||||||
|
const startX = 10;
|
||||||
|
const startY = this.currentY + 20;
|
||||||
|
const itemWidth = (canvasWidth - startX * 2) / cols - 18;
|
||||||
|
const itemHeight = 200; // 每个题目的高度(增加高度以容纳三层结构)
|
||||||
|
|
||||||
|
for (let row = 0; row < rows; row++) {
|
||||||
|
for (let col = 0; col < cols; col++) {
|
||||||
|
const index = row * cols + col;
|
||||||
|
if (index >= problems.length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const problem = problems[index];
|
||||||
|
const x = startX + col * itemWidth;
|
||||||
|
const y = startY + row * itemHeight;
|
||||||
|
// 绘制单个题目
|
||||||
|
this.drawSingleProblem(
|
||||||
|
ctx,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
itemWidth,
|
||||||
|
itemHeight,
|
||||||
|
problem,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制单个题目
|
||||||
|
*/
|
||||||
|
private drawSingleProblem(
|
||||||
|
ctx: RenderingContext,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
width: number,
|
||||||
|
_height: number,
|
||||||
|
problem: { left: number; right: number; result: number },
|
||||||
|
) {
|
||||||
|
const blueColor = '#8CBAFF';
|
||||||
|
const yellowColor = '#FFCB05';
|
||||||
|
const greenColor = '#5AE2B1';
|
||||||
|
const pinkColor = '#F2A4C0';
|
||||||
|
const lineColor = '#6CD2EA';
|
||||||
|
|
||||||
|
// 确定大数和小数
|
||||||
|
const bigNumber = Math.max(problem.left, problem.right);
|
||||||
|
const smallNumber = Math.min(problem.left, problem.right);
|
||||||
|
const bigFirst = problem.left >= problem.right;
|
||||||
|
|
||||||
|
const boxSize = 30; // 方框大小
|
||||||
|
const fontSize = 18; // 数字字体大小
|
||||||
|
const verticalSpacing = 25; // 垂直间距(缩小)
|
||||||
|
const nodeSpacing = 40; // 二叉树节点之间的水平间距
|
||||||
|
const horizontalSpacing = 10; // 第一层元素之间的水平间距
|
||||||
|
|
||||||
|
// 第一层:原计算题
|
||||||
|
const firstLayerY = y + 15;
|
||||||
|
const centerX = x + width / 2;
|
||||||
|
|
||||||
|
// 计算第一个加数的位置(大数或小数,取决于顺序)
|
||||||
|
const firstNumber = bigFirst ? bigNumber : smallNumber;
|
||||||
|
const secondNumber = bigFirst ? smallNumber : bigNumber;
|
||||||
|
|
||||||
|
// 第一层元素位置(间距为15)
|
||||||
|
const firstBoxX = centerX - boxSize - horizontalSpacing;
|
||||||
|
const plusX = firstBoxX + boxSize + horizontalSpacing;
|
||||||
|
const secondBoxX = plusX + horizontalSpacing;
|
||||||
|
const equalsX = secondBoxX + boxSize + horizontalSpacing - 2;
|
||||||
|
const answerBoxX = equalsX + 10 + horizontalSpacing;
|
||||||
|
|
||||||
|
// 绘制第一个加数方框(边框1px,#999,无填充)
|
||||||
|
this.drawTopLayerBox(
|
||||||
|
ctx,
|
||||||
|
firstBoxX,
|
||||||
|
firstLayerY,
|
||||||
|
boxSize,
|
||||||
|
firstNumber,
|
||||||
|
fontSize,
|
||||||
|
blueColor,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 绘制加号
|
||||||
|
this.drawPlusSign(ctx, plusX, firstLayerY + boxSize / 2, 12);
|
||||||
|
|
||||||
|
// 绘制第二个加数方框
|
||||||
|
this.drawTopLayerBox(
|
||||||
|
ctx,
|
||||||
|
secondBoxX,
|
||||||
|
firstLayerY,
|
||||||
|
boxSize,
|
||||||
|
secondNumber,
|
||||||
|
fontSize,
|
||||||
|
yellowColor,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 绘制等号
|
||||||
|
this.drawEqualsSign(ctx, equalsX, firstLayerY + boxSize / 2, 12);
|
||||||
|
|
||||||
|
// 绘制答案框(空白)
|
||||||
|
this.drawSquareBox(ctx, answerBoxX, firstLayerY, boxSize, greenColor);
|
||||||
|
|
||||||
|
// 第二层:在较小加数下绘制二叉树结构(两个空方框)
|
||||||
|
const secondLayerY = firstLayerY + boxSize + verticalSpacing;
|
||||||
|
const smallBoxX = bigFirst ? secondBoxX : firstBoxX;
|
||||||
|
const smallBoxCenterX = smallBoxX + boxSize / 2;
|
||||||
|
|
||||||
|
// 绘制二叉树的两个子节点(空方框)
|
||||||
|
const leftNodeX = smallBoxCenterX - nodeSpacing / 2 - boxSize / 2;
|
||||||
|
const rightNodeX = smallBoxCenterX + nodeSpacing / 2 - boxSize / 2;
|
||||||
|
|
||||||
|
// 绘制左子节点(空方框)
|
||||||
|
this.drawSquareBox(ctx, leftNodeX, secondLayerY, boxSize, blueColor);
|
||||||
|
|
||||||
|
// 绘制右子节点(空方框)
|
||||||
|
this.drawSquareBox(ctx, rightNodeX, secondLayerY, boxSize, pinkColor);
|
||||||
|
|
||||||
|
// 确定哪个子节点与小数相连
|
||||||
|
// 如果小数在前(bigFirst=false),第二个方框(右子节点)和加数相连
|
||||||
|
// 如果小数在后(bigFirst=true),第一个方框(左子节点)和加数相连
|
||||||
|
const connectedNodeX = bigFirst ? leftNodeX : rightNodeX;
|
||||||
|
const connectedNodeCenterX = connectedNodeX + boxSize / 2;
|
||||||
|
const unconnectedNodeX = bigFirst ? rightNodeX : leftNodeX;
|
||||||
|
const unconnectedNodeCenterX = unconnectedNodeX + boxSize / 2;
|
||||||
|
|
||||||
|
// 绘制连接线(从较小加数到两个子节点)
|
||||||
|
ctx.strokeStyle = lineColor;
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(smallBoxCenterX, firstLayerY + boxSize);
|
||||||
|
ctx.lineTo(leftNodeX + boxSize / 2, secondLayerY);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(smallBoxCenterX, firstLayerY + boxSize);
|
||||||
|
ctx.lineTo(rightNodeX + boxSize / 2, secondLayerY);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
const thirdLayerY = secondLayerY + boxSize + verticalSpacing + 10;
|
||||||
|
|
||||||
|
let bigBoxX = 0;
|
||||||
|
let bigBoxCenterX = 0;
|
||||||
|
let thirdBoxX = 0;
|
||||||
|
let thirdLineEndX = 0;
|
||||||
|
let firstPlusX = 0;
|
||||||
|
let secondPlusX = 0;
|
||||||
|
let thirdBoxCenterX = 0;
|
||||||
|
if (bigFirst) {
|
||||||
|
bigBoxX = firstBoxX;
|
||||||
|
bigBoxCenterX = bigBoxX + boxSize / 2;
|
||||||
|
thirdBoxX = bigBoxCenterX;
|
||||||
|
thirdBoxCenterX = thirdBoxX + boxSize / 2;
|
||||||
|
|
||||||
|
firstPlusX = bigBoxX + boxSize;
|
||||||
|
secondPlusX = secondBoxX + boxSize / 2;
|
||||||
|
|
||||||
|
thirdLineEndX = thirdBoxX + boxSize;
|
||||||
|
} else {
|
||||||
|
bigBoxX = secondBoxX;
|
||||||
|
bigBoxCenterX = bigBoxX + boxSize / 2;
|
||||||
|
thirdBoxX = bigBoxX - boxSize / 2;
|
||||||
|
thirdBoxCenterX = thirdBoxX + boxSize / 2;
|
||||||
|
|
||||||
|
firstPlusX = secondBoxX;
|
||||||
|
secondPlusX = firstBoxX + boxSize / 2;
|
||||||
|
thirdLineEndX = thirdBoxX;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 绘制第三层方框(空方框)
|
||||||
|
this.drawSquareBox(ctx, thirdBoxX, thirdLayerY, boxSize, blueColor);
|
||||||
|
|
||||||
|
// 从较大加数正下方绘制直线至第2.5层的位置
|
||||||
|
const layer2_5Y =
|
||||||
|
secondLayerY +
|
||||||
|
boxSize +
|
||||||
|
(thirdLayerY - secondLayerY - boxSize) / 2 +
|
||||||
|
4;
|
||||||
|
ctx.strokeStyle = '#888';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(bigBoxCenterX, firstLayerY + boxSize);
|
||||||
|
ctx.lineTo(bigBoxCenterX, layer2_5Y);
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
// 计算相交点(第2.5层位置,在bigBoxCenterX处)
|
||||||
|
const intersectionY = layer2_5Y;
|
||||||
|
// ctx.strokeStyle = 'red';
|
||||||
|
// 从第二层与小数相连的方框下绘制直角折线到相交点
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(connectedNodeCenterX, secondLayerY + boxSize);
|
||||||
|
ctx.lineTo(connectedNodeCenterX, intersectionY); // 垂直向下
|
||||||
|
ctx.lineTo(bigBoxCenterX, intersectionY); // 水平到相交点
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
// 绘制相交点到第三层方框的直线
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(thirdBoxCenterX, intersectionY);
|
||||||
|
ctx.lineTo(thirdBoxCenterX, thirdLayerY); // 水平到相交点
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
// 在相交位置绘制小加号(使用drawSymbol方法)
|
||||||
|
this.drawSymbol(firstPlusX, layer2_5Y - 10, '+', 12);
|
||||||
|
|
||||||
|
// ctx.strokeStyle = 'blue';
|
||||||
|
// 从第二层另一个方框(未与小数相连的)下绘制直角折线连接第三层方框
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(unconnectedNodeCenterX, secondLayerY + boxSize);
|
||||||
|
ctx.lineTo(unconnectedNodeCenterX, thirdLayerY + boxSize / 2); // 垂直向下到第三层
|
||||||
|
ctx.lineTo(thirdLineEndX, thirdLayerY + boxSize / 2); // 水平连接到第三层方框中心
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
// 在第二层另一个方框和第三层方框之间的折线中间绘制加号
|
||||||
|
this.drawSymbol(secondPlusX, thirdLayerY + 3, '+', 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制第一层方框(边框1px,#999,无填充,显示数字)
|
||||||
|
*/
|
||||||
|
private drawTopLayerBox(
|
||||||
|
ctx: RenderingContext,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
size: number,
|
||||||
|
number: number,
|
||||||
|
fontSize: number,
|
||||||
|
color: string,
|
||||||
|
) {
|
||||||
|
// 绘制方框边框(1px,#999,无填充)
|
||||||
|
// ctx.strokeStyle = '#999';
|
||||||
|
// ctx.lineWidth = 1;
|
||||||
|
// ctx.setLineDash([]);
|
||||||
|
// ctx.strokeRect(x, y, size, size);
|
||||||
|
this.drawSquareBox(ctx, x, y, size, color);
|
||||||
|
|
||||||
|
// 绘制数字
|
||||||
|
ctx.fillStyle = '#000';
|
||||||
|
ctx.font = `bold ${fontSize}px "YouYuan", "PingFang SC", "Microsoft Yahei", sans-serif`;
|
||||||
|
ctx.textAlign = 'center';
|
||||||
|
ctx.textBaseline = 'middle';
|
||||||
|
ctx.fillText(String(number), x + size / 2, y + size / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制加号
|
||||||
|
*/
|
||||||
|
private drawPlusSign(
|
||||||
|
ctx: RenderingContext,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
size: number,
|
||||||
|
) {
|
||||||
|
ctx.strokeStyle = '#000';
|
||||||
|
ctx.lineWidth = 1.5;
|
||||||
|
ctx.beginPath();
|
||||||
|
// 横线
|
||||||
|
ctx.moveTo(x - size / 2, y);
|
||||||
|
ctx.lineTo(x + size / 2, y);
|
||||||
|
// 竖线
|
||||||
|
ctx.moveTo(x, y - size / 2);
|
||||||
|
ctx.lineTo(x, y + size / 2);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制等号
|
||||||
|
*/
|
||||||
|
private drawEqualsSign(
|
||||||
|
ctx: RenderingContext,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
size: number,
|
||||||
|
) {
|
||||||
|
ctx.strokeStyle = '#000';
|
||||||
|
ctx.lineWidth = 1.5;
|
||||||
|
ctx.beginPath();
|
||||||
|
// 上横线
|
||||||
|
ctx.moveTo(x, y - size / 3);
|
||||||
|
ctx.lineTo(x + size, y - size / 3);
|
||||||
|
// 下横线
|
||||||
|
ctx.moveTo(x, y + size / 3);
|
||||||
|
ctx.lineTo(x + size, y + size / 3);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MakeTenDraw;
|
||||||
@@ -424,4 +424,43 @@ export class BaseDrawService {
|
|||||||
// 绘制内容区域分割线
|
// 绘制内容区域分割线
|
||||||
this.drawDivider();
|
this.drawDivider();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制空白方框(边框1px,#999,无填充,不显示数字)
|
||||||
|
*/
|
||||||
|
drawBox(
|
||||||
|
ctx: RenderingContext,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
color: string = '#999',
|
||||||
|
lineWidth: number = 1,
|
||||||
|
) {
|
||||||
|
// 绘制方框边框(1px,#999,无填充)
|
||||||
|
ctx.strokeStyle = color;
|
||||||
|
ctx.lineWidth = lineWidth;
|
||||||
|
ctx.setLineDash([]);
|
||||||
|
ctx.strokeRect(x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制正方形方框(调用drawBox,减少参数)
|
||||||
|
* @param ctx 渲染上下文
|
||||||
|
* @param x 方框左上角x
|
||||||
|
* @param y 方框左上角y
|
||||||
|
* @param size 方框边长
|
||||||
|
* @param color 边框颜色(可选,默认为#999)
|
||||||
|
* @param lineWidth 线宽(可选,默认为1)
|
||||||
|
*/
|
||||||
|
drawSquareBox(
|
||||||
|
ctx: RenderingContext,
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
size: number,
|
||||||
|
color: string = '#999',
|
||||||
|
lineWidth: number = 1,
|
||||||
|
) {
|
||||||
|
this.drawBox(ctx, x, y, size, size, color, lineWidth);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,12 +23,19 @@
|
|||||||
"condition": {
|
"condition": {
|
||||||
"miniprogram": {
|
"miniprogram": {
|
||||||
"list": [
|
"list": [
|
||||||
|
{
|
||||||
|
"name": "mathPages/makeTen/makeTen",
|
||||||
|
"pathName": "mathPages/makeTen/makeTen",
|
||||||
|
"query": "id=make-ten",
|
||||||
|
"scene": null,
|
||||||
|
"launchMode": "default"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "focusPages/dotConnect/dotConnect",
|
"name": "focusPages/dotConnect/dotConnect",
|
||||||
"pathName": "focusPages/dotConnect/dotConnect",
|
"pathName": "focusPages/dotConnect/dotConnect",
|
||||||
"query": "id=dot-connect",
|
"query": "id=dot-connect",
|
||||||
"scene": null,
|
"launchMode": "default",
|
||||||
"launchMode": "default"
|
"scene": null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "mathPages/numberObjectMatch/numberObjectMatch",
|
"name": "mathPages/numberObjectMatch/numberObjectMatch",
|
||||||
|
|||||||
Reference in New Issue
Block a user