diff --git a/miniprogram/app.json b/miniprogram/app.json index 960d354..151c1a8 100644 --- a/miniprogram/app.json +++ b/miniprogram/app.json @@ -9,9 +9,21 @@ "subPackages": [ { "root": "mathPages", - "pages": ["numberColor/numberColor"] + "name": "mathPages", + "pages": ["numberColor/numberColor"], + "independent": false } ], + "preloadRule": { + "pages/index/index": { + "network": "all", + "packages": ["mathPages"] + }, + "pages/mathIndex/mathIndex": { + "network": "all", + "packages": ["mathPages"] + } + }, "window": {}, "style": "v2", "rendererOptions": { @@ -48,17 +60,17 @@ "selectedIconPath": "assets/tabBar/icon-math-active.png", "text": "数学" }, - { - "pagePath": "pages/copyBook/copyBook", - "iconPath": "assets/tabBar/icon-edit.png", - "selectedIconPath": "assets/tabBar/icon-edit-active.png", - "text": "练字" - }, { "pagePath": "pages/shape/index", "iconPath": "assets/tabBar/icon-shape.png", "selectedIconPath": "assets/tabBar/icon-shape-active.png", "text": "图形" + }, + { + "pagePath": "pages/copyBook/copyBook", + "iconPath": "assets/tabBar/icon-edit.png", + "selectedIconPath": "assets/tabBar/icon-edit-active.png", + "text": "练字" } ] } diff --git a/miniprogram/constants/mathFunctions.ts b/miniprogram/constants/mathFunctions.ts new file mode 100644 index 0000000..31f8a6a --- /dev/null +++ b/miniprogram/constants/mathFunctions.ts @@ -0,0 +1,78 @@ +export interface MathFunctionType { + id: string; + page?: string; + title: string; + desc: string; + icon: string; +} + +export const MATH_FUNCTION_TYPES: MathFunctionType[] = [ + { + id: 'number-find', + page: 'numberColor', + title: '看数字,涂一涂', + desc: '看数字,找一找下面相同的数字,涂上颜色', + icon: '🔍', + }, + { + id: 'number-write', + page: 'numberColor', + title: '看数字,写一写', + desc: '看数字,按笔画顺序写一写', + icon: '✏️', + }, + { + id: 'number-coloring', + title: '数字涂色卡', + desc: '一边写数字、一边学数数,数字和卡通图片一一对应', + icon: '🎨', + }, + { + id: 'counting-matching', + title: '数一数,连一连', + desc: '通过连线配对数字和对应的数量图形', + icon: '🔗', + }, + { + id: 'missing-number', + title: '填上缺少的数字', + desc: '在数字序列中找出并填写缺失的数字', + icon: '❓', + }, + { + id: 'compare', + title: '数一数,比大小', + desc: '通过数数比较两组物品的数量大小', + icon: '⚖️', + }, + { + id: 'counting-select', + title: '数一数,选一选', + desc: '数出物品数量,从多个选项中选择正确答案', + icon: '✓', + }, + { + id: 'counting-fill', + title: '数一数,填一填', + desc: '数出物品数量,填写对应的数字', + icon: '✏️', + }, + { + id: 'addition-5', + title: '5以内加法', + desc: '练习5以内的加法运算,图形化展示', + icon: '➕', + }, + { + id: 'addition-10', + title: '10以内加法', + desc: '练习10以内的加法运算,图形化展示', + icon: '➕', + }, + { + id: 'addition-subtraction-10', + title: '10以内加减法', + desc: '练习10以内的加法和减法混合运算', + icon: '±', + }, +]; diff --git a/miniprogram/mathPages/assets/animal-number/animal-number-1.png b/miniprogram/mathPages/assets/animal-number/animal-number-1.png index fa2a4e3..b1a7473 100644 Binary files a/miniprogram/mathPages/assets/animal-number/animal-number-1.png and b/miniprogram/mathPages/assets/animal-number/animal-number-1.png differ diff --git a/miniprogram/mathPages/assets/animal-number/animal-number-10.png b/miniprogram/mathPages/assets/animal-number/animal-number-10.png index 7ce9018..4e62440 100644 Binary files a/miniprogram/mathPages/assets/animal-number/animal-number-10.png and b/miniprogram/mathPages/assets/animal-number/animal-number-10.png differ diff --git a/miniprogram/mathPages/assets/animal-number/animal-number-2.png b/miniprogram/mathPages/assets/animal-number/animal-number-2.png index 14c0aa1..cb8ad1e 100644 Binary files a/miniprogram/mathPages/assets/animal-number/animal-number-2.png and b/miniprogram/mathPages/assets/animal-number/animal-number-2.png differ diff --git a/miniprogram/mathPages/assets/animal-number/animal-number-3.png b/miniprogram/mathPages/assets/animal-number/animal-number-3.png index 685f9f5..1922453 100644 Binary files a/miniprogram/mathPages/assets/animal-number/animal-number-3.png and b/miniprogram/mathPages/assets/animal-number/animal-number-3.png differ diff --git a/miniprogram/mathPages/assets/animal-number/animal-number-4.png b/miniprogram/mathPages/assets/animal-number/animal-number-4.png index b695473..976c188 100644 Binary files a/miniprogram/mathPages/assets/animal-number/animal-number-4.png and b/miniprogram/mathPages/assets/animal-number/animal-number-4.png differ diff --git a/miniprogram/mathPages/assets/animal-number/animal-number-5.png b/miniprogram/mathPages/assets/animal-number/animal-number-5.png index a454876..d6dc2d0 100644 Binary files a/miniprogram/mathPages/assets/animal-number/animal-number-5.png and b/miniprogram/mathPages/assets/animal-number/animal-number-5.png differ diff --git a/miniprogram/mathPages/assets/animal-number/animal-number-6.png b/miniprogram/mathPages/assets/animal-number/animal-number-6.png index 0fbde14..dac0f83 100644 Binary files a/miniprogram/mathPages/assets/animal-number/animal-number-6.png and b/miniprogram/mathPages/assets/animal-number/animal-number-6.png differ diff --git a/miniprogram/mathPages/assets/animal-number/animal-number-7.png b/miniprogram/mathPages/assets/animal-number/animal-number-7.png index 78b6305..f35d349 100644 Binary files a/miniprogram/mathPages/assets/animal-number/animal-number-7.png and b/miniprogram/mathPages/assets/animal-number/animal-number-7.png differ diff --git a/miniprogram/mathPages/assets/animal-number/animal-number-8.png b/miniprogram/mathPages/assets/animal-number/animal-number-8.png index 89d8abe..3b3a821 100644 Binary files a/miniprogram/mathPages/assets/animal-number/animal-number-8.png and b/miniprogram/mathPages/assets/animal-number/animal-number-8.png differ diff --git a/miniprogram/mathPages/assets/animal-number/animal-number-9.png b/miniprogram/mathPages/assets/animal-number/animal-number-9.png index 2cf166c..2b80677 100644 Binary files a/miniprogram/mathPages/assets/animal-number/animal-number-9.png and b/miniprogram/mathPages/assets/animal-number/animal-number-9.png differ diff --git a/miniprogram/mathPages/assets/finger/finger-1.png b/miniprogram/mathPages/assets/finger/finger-1.png index 7989b4d..ee6e240 100644 Binary files a/miniprogram/mathPages/assets/finger/finger-1.png and b/miniprogram/mathPages/assets/finger/finger-1.png differ diff --git a/miniprogram/mathPages/assets/finger/finger-10.png b/miniprogram/mathPages/assets/finger/finger-10.png index 36df6a1..e16f8ba 100644 Binary files a/miniprogram/mathPages/assets/finger/finger-10.png and b/miniprogram/mathPages/assets/finger/finger-10.png differ diff --git a/miniprogram/mathPages/assets/finger/finger-2.png b/miniprogram/mathPages/assets/finger/finger-2.png index 5b708e4..7b2feab 100644 Binary files a/miniprogram/mathPages/assets/finger/finger-2.png and b/miniprogram/mathPages/assets/finger/finger-2.png differ diff --git a/miniprogram/mathPages/assets/finger/finger-3.png b/miniprogram/mathPages/assets/finger/finger-3.png index 0acc6b4..cdaae18 100644 Binary files a/miniprogram/mathPages/assets/finger/finger-3.png and b/miniprogram/mathPages/assets/finger/finger-3.png differ diff --git a/miniprogram/mathPages/assets/finger/finger-4.png b/miniprogram/mathPages/assets/finger/finger-4.png index 7a05898..bc7f7f9 100644 Binary files a/miniprogram/mathPages/assets/finger/finger-4.png and b/miniprogram/mathPages/assets/finger/finger-4.png differ diff --git a/miniprogram/mathPages/assets/finger/finger-5.png b/miniprogram/mathPages/assets/finger/finger-5.png index 712d523..9e1ed5e 100644 Binary files a/miniprogram/mathPages/assets/finger/finger-5.png and b/miniprogram/mathPages/assets/finger/finger-5.png differ diff --git a/miniprogram/mathPages/assets/finger/finger-6.png b/miniprogram/mathPages/assets/finger/finger-6.png index f6d29a0..3c25d57 100644 Binary files a/miniprogram/mathPages/assets/finger/finger-6.png and b/miniprogram/mathPages/assets/finger/finger-6.png differ diff --git a/miniprogram/mathPages/assets/finger/finger-7.png b/miniprogram/mathPages/assets/finger/finger-7.png index 3e43b29..a279788 100644 Binary files a/miniprogram/mathPages/assets/finger/finger-7.png and b/miniprogram/mathPages/assets/finger/finger-7.png differ diff --git a/miniprogram/mathPages/assets/finger/finger-8.png b/miniprogram/mathPages/assets/finger/finger-8.png index 52260bf..8f4da20 100644 Binary files a/miniprogram/mathPages/assets/finger/finger-8.png and b/miniprogram/mathPages/assets/finger/finger-8.png differ diff --git a/miniprogram/mathPages/assets/finger/finger-9.png b/miniprogram/mathPages/assets/finger/finger-9.png index 4df9fac..ec3b50d 100644 Binary files a/miniprogram/mathPages/assets/finger/finger-9.png and b/miniprogram/mathPages/assets/finger/finger-9.png differ diff --git a/miniprogram/mathPages/numberColor/numberColor.less b/miniprogram/mathPages/numberColor/numberColor.less index 3847f10..ec2f015 100644 --- a/miniprogram/mathPages/numberColor/numberColor.less +++ b/miniprogram/mathPages/numberColor/numberColor.less @@ -47,22 +47,6 @@ page { overflow: hidden; } - // .canvas-wrapper { - // width: 100%; - // margin-bottom: 40rpx; - // display: flex; - // justify-content: center; - // align-items: center; - // background: #f8f8f8; - // border-radius: 12rpx; - // padding: 20rpx; - // box-sizing: border-box; - // } - - // .canvas-content { - // width: 100%; - // height: 100%; - // } } /* 数字选择区域 */ @@ -70,17 +54,18 @@ page { display: flex; flex-direction: column; gap: 20rpx; + margin-top: 40rpx; } .number-row { display: flex; flex-direction: row; - gap: 60rpx; + gap: 40rpx; width: 100%; - margin-top: 40rpx; } .number-item { + height: 90rpx; background: #ffffff; border: 2rpx solid #e8e8e8; border-radius: 16rpx; @@ -90,26 +75,43 @@ page { display: flex; align-items: center; justify-content: center; - flex: 1; box-sizing: border-box; - min-width: 0; position: relative; + flex: 1; + min-width: 0; + box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08), 0 2rpx 4rpx rgba(0, 0, 0, 0.06); &:active { transform: scale(0.98); + box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.1), 0 1rpx 2rpx rgba(0, 0, 0, 0.08); } &.active { border-color: #93d333; - box-shadow: 0 0 0 4rpx rgba(147, 211, 51, 0.2); + box-shadow: 0 4rpx 16rpx rgba(147, 211, 51, 0.25), 0 0 0 4rpx rgba(147, 211, 51, 0.15); } .number-text { - font-size: 28rpx; - color: #141414; + font-size: 36rpx; font-weight: bold; + color: #141414; text-align: center; } +} + +.number-column { + flex: 1; + display: flex; + flex-direction: row; + gap: 40rpx; + + .number-item { + flex: 1; + } + + .random-button { + flex: 2; + } /* 随机按钮样式 */ &.random-button { @@ -134,7 +136,7 @@ page { } .number-text { - // flex: 0; + flex-shrink: 0; } &.active { @@ -154,13 +156,12 @@ page { left: 0; bottom: 0; width: 100%; - height: 200rpx; + height: 180rpx; display: flex; justify-content: space-between; - align-items: center; background-color: #fff; box-shadow: 0px -3.9rpx 5.2rpx rgba(0, 0, 0, 0.15); - padding: 0 24rpx; + padding: 24rpx; padding-bottom: env(safe-area-inset-bottom); box-sizing: border-box; border-radius: 16rpx 16rpx 0 0; diff --git a/miniprogram/mathPages/numberColor/numberColor.ts b/miniprogram/mathPages/numberColor/numberColor.ts index cbea790..4dba43f 100644 --- a/miniprogram/mathPages/numberColor/numberColor.ts +++ b/miniprogram/mathPages/numberColor/numberColor.ts @@ -1,12 +1,18 @@ import { PAPER_SIZE } from '../../constants/colors'; import { checkAndSaveImage } from '../../utils/saveImage'; import { shouldShowShareGuide } from '../../utils/shareGuide'; +import NumberColorDraw from '../service/numberColorDraw'; +import { + MATH_FUNCTION_TYPES, + MathFunctionType, +} from '../../constants/mathFunctions'; Page({ canvas: null as Canvas | null, ctx: null as RenderingContext | null, boxHeight: 0, boxWidth: 0, + drawService: null as NumberColorDraw | null, data: { pageTitle: '看数字,涂一涂', // 默认标题 @@ -18,26 +24,17 @@ Page({ onLoad(options: { id?: string }) { // 根据id参数判断页面标题 - const functionId = options.id || 'number-find-color'; + const functionId = options.id || 'number-find'; this.setData({ functionId, }); // 根据functionId设置页面标题 - const titleMap: Record = { - 'number-find-color': '看数字,涂一涂', - 'number-coloring': '数字涂色卡', - 'counting-matching': '数一数,连一连', - 'missing-number': '填上缺少的数字', - compare: '数一数,比大小', - 'counting-select': '数一数,选一选', - 'counting-fill': '数一数,填一填', - 'addition-5': '5以内加法', - 'addition-10': '10以内加法', - 'addition-subtraction-10': '10以内加减法', - }; + const functionItem = MATH_FUNCTION_TYPES.find( + (item: MathFunctionType) => item.id === functionId, + ); - const pageTitle = titleMap[functionId] || '看数字,涂一涂'; + const pageTitle = functionItem?.title || '看数字,涂一涂'; this.setData({ pageTitle, }); @@ -91,6 +88,26 @@ Page({ this.canvas = canvasNode; this.ctx = ctx; + // 初始化绘制服务 + this.drawService = new NumberColorDraw( + canvasNode, + ctx, + { + title: this.data.pageTitle, + subTitle: '找一找下面相同的数字,涂上颜色', + functionId: this.data.functionId, + }, + ); + + // 如果还没有选中数字,随机选择一个 + if (this.data.selectedNumber === 0) { + const randomNumber = + Math.floor(Math.random() * 10) + 1; + this.setData({ + selectedNumber: randomNumber, + }); + } + // 绘制初始内容 this.drawCanvas(); } @@ -103,34 +120,17 @@ Page({ /** * 绘制Canvas内容 */ - drawCanvas() { - if (!this.ctx) { + async drawCanvas() { + if (!this.ctx || !this.drawService) { return; } - const ctx = this.ctx; - const width = this.boxWidth; - const height = this.boxHeight; - - // 清空画布 - ctx.clearRect(0, 0, width, height); - - // 设置背景色 - ctx.fillStyle = '#FFFFFF'; - ctx.fillRect(0, 0, width, height); - - // TODO: 根据选中的数字绘制内容 if (this.data.selectedNumber > 0) { - // 绘制示例:显示选中的数字 - ctx.fillStyle = '#141414'; - ctx.font = 'bold 120px sans-serif'; - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - ctx.fillText( - String(this.data.selectedNumber), - width / 2, - height / 2, - ); + try { + await this.drawService.draw(this.data.selectedNumber); + } catch (error) { + console.error('绘制失败:', error); + } } }, diff --git a/miniprogram/mathPages/numberColor/numberColor.wxml b/miniprogram/mathPages/numberColor/numberColor.wxml index af0849d..c4a59af 100644 --- a/miniprogram/mathPages/numberColor/numberColor.wxml +++ b/miniprogram/mathPages/numberColor/numberColor.wxml @@ -43,21 +43,28 @@ - - {{number}} - - - - + + + {{number}} - 随机 + + + + 随机 + diff --git a/miniprogram/mathPages/service/baseMathDraw.ts b/miniprogram/mathPages/service/baseMathDraw.ts new file mode 100644 index 0000000..5823630 --- /dev/null +++ b/miniprogram/mathPages/service/baseMathDraw.ts @@ -0,0 +1,142 @@ +import { PAPER_SIZE } from '../../constants/colors'; +import { drawMathHeader, drawMathMiniHeader } from './mathHeaderDraw'; + +/** + * 基础数学绘制服务 + * 包含Paper设置和Header绘制功能,可被其他绘制服务复用 + */ +export class BaseMathDrawService { + headerType: PrintHeader = 'wechat'; + canvas: WechatMiniprogram.Canvas; + ctx: RenderingContext; + options: Record; + paperSize: PaperSize; + currentX: number; + currentY: number; + canvasWidth: number; // 逻辑像素宽度 + canvasHeight: number; // 逻辑像素高度 + + constructor( + canvas: Canvas, + ctx: RenderingContext, + options?: Record, + ) { + options = options || {}; + this.canvas = canvas; + this.ctx = ctx; + this.paperSize = 'A4'; + this.options = { + appName: '涂鸦丫小程序', + appHint: '在玩耍中学习数学', + title: '看数字,涂一涂', + subTitle: '找一找下面相同的数字,涂上颜色', + ...options, + }; + this.currentX = 0; + this.currentY = 0; + this.canvasWidth = 0; + this.canvasHeight = 0; + this.setPrintConfig(); + } + + setPrintConfig() { + const printConfig = getApp().getPrintConfig(); + this.headerType = printConfig.header; + this.options.appName = printConfig.appName; + } + + /** + * 设置Paper(逻辑像素,尺寸除以3) + */ + setPaper() { + const { ctx, canvas } = this; + const { pixelRatio: dpr } = wx.getWindowInfo(); + let { width, height } = PAPER_SIZE[this.paperSize]; + console.log('width', width); + console.log('height', height); + console.log('dpr', dpr); + + this.canvasWidth = width; + this.canvasHeight = height; + + // 设置 canvas 为物理像素尺寸(用于高分辨率显示) + const physicalWidth = width * dpr; + const physicalHeight = height * dpr; + canvas.width = physicalWidth; + canvas.height = physicalHeight; + + // 重置 transform 并 scale 到逻辑像素 + ctx.setTransform(1, 0, 0, 1, 0, 0); // 重置 transform + ctx.scale(dpr, dpr); // scale 到逻辑像素,后续绘制都使用逻辑像素 + + this.clear(); + ctx.fillStyle = '#fff'; + // 使用逻辑像素尺寸填充 + ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight); + } + + /** + * 清除画布 + */ + clear() { + const canvas = this.canvas; + this.ctx.clearRect(0, 0, canvas.width, canvas.height); + } + + /** + * 绘制Header(逻辑像素,尺寸除以3) + */ + async drawHeader() { + this.currentX = 24; + this.currentY = 24; + await drawMathHeader({ + canvas: this.canvas, + ctx: this.ctx, + headerType: this.headerType, + options: { + appName: this.options.appName || '涂鸦丫小程序', + appHint: this.options.appHint || '识字|识图|练字|打印', + title: this.options.title || '看数字,涂一涂', + subTitle: + this.options.subTitle || '找一找下面相同的数字,涂上颜色', + }, + onHeaderDrawn: (currentY) => { + this.currentY = currentY; + }, + }); + } + + /** + * 绘制迷你Header(逻辑像素,尺寸除以3) + */ + drawMiniHeader() { + drawMathMiniHeader({ + ctx: this.ctx, + canvasWidth: this.canvasWidth, + options: { + appName: this.options.appName || '涂鸦丫小程序', + title: this.options.title || '看数字,涂一涂', + }, + onHeaderDrawn: (currentY) => { + this.currentY = currentY; + }, + }); + } + + /** + * 绘制分割线(逻辑像素,尺寸除以3) + */ + drawDivider() { + const { ctx, canvasWidth } = this; + const dividerY = this.currentY + 10; // 10px间距 + + ctx.strokeStyle = '#000'; + ctx.lineWidth = 1; + ctx.beginPath(); + ctx.moveTo(24, dividerY); + ctx.lineTo(canvasWidth - 24, dividerY); + ctx.stroke(); + + this.currentY = dividerY + 10; // 分割线下方10px间距 + } +} diff --git a/miniprogram/mathPages/service/mathHeaderDraw.ts b/miniprogram/mathPages/service/mathHeaderDraw.ts new file mode 100644 index 0000000..9d4c5bd --- /dev/null +++ b/miniprogram/mathPages/service/mathHeaderDraw.ts @@ -0,0 +1,129 @@ +import { getMiniCodeImage, getImage } from '../../utils/index'; + +/** + * 绘制数学模块页眉的参数接口(尺寸除以3) + */ +interface DrawMathHeaderParams { + canvas: WechatMiniprogram.Canvas; + ctx: RenderingContext; + headerType: PrintHeader; + options: { + appName: string; + appHint: string; + title: string; + subTitle: string; + }; + onHeaderDrawn?: (currentY: number) => void; +} + +/** + * 绘制数学模块完整页眉(尺寸除以3) + */ +export async function drawMathHeader({ + canvas, + ctx, + headerType, + options, + onHeaderDrawn, +}: DrawMathHeaderParams): Promise { + const { appName, appHint, title, subTitle } = options; + + let titleX = 108; // 约109.33 + const titleY = 26; // 约26.67 + + const logoX = 24; // 约26.67 + const logoY = 20; // 20 + const logoWidth = 65; // 约66.67 + const logoHeight = 65; // 约66.67 + + // 根据 headerType 绘制 Logo 或调整标题位置 + switch (headerType) { + case 'LogoImage': { + const image = await getImage( + canvas, + '/assets/imgs/doodle-logo.png', + ); + ctx.drawImage(image, logoX, logoY, logoWidth, logoHeight); + break; + } + case 'noLogoImage': { + titleX = 40; + break; + } + case 'minimal': { + titleX = 40; + break; + } + default: { + const image = await getMiniCodeImage(canvas); + ctx.drawImage(image, logoX, logoY, logoWidth, logoHeight); + break; + } + } + + // 绘制应用名称(字体大小除以3) + ctx.font = 'bold 22px "Microsoft Yahei"'; + ctx.fillStyle = '#000'; + ctx.textAlign = 'left'; + ctx.textBaseline = 'top'; + ctx.fillText(appName, titleX, titleY); + + // 绘制应用提示(字体大小除以3) + ctx.font = '16px "Microsoft Yahei"'; + ctx.fillStyle = '#666'; + ctx.fillText(appHint, titleX, 66); + + // 绘制标题(字体大小除以3) + ctx.font = 'bold 22px "Microsoft Yahei"'; + ctx.fillStyle = '#000'; + ctx.fillText(title, 280, titleY); + + // 绘制副标题(字体大小除以3) + ctx.font = '16px "Microsoft Yahei"'; + ctx.fillStyle = '#666'; + ctx.fillText(subTitle, 280, 66); + + // 调用回调函数 + if (onHeaderDrawn) { + onHeaderDrawn(100); + } +} + +/** + * 绘制数学模块迷你页眉的参数接口(尺寸除以3) + */ +interface DrawMathMiniHeaderParams { + // canvas: WechatMiniprogram.Canvas; + ctx: RenderingContext; + options: { + appName: string; + title: string; + }; + canvasWidth: number; // 逻辑像素宽度(已除以3) + onHeaderDrawn?: (currentY: number) => void; +} + +/** + * 绘制数学模块迷你页眉(尺寸除以3) + */ +export function drawMathMiniHeader({ + ctx, + options, + canvasWidth, + onHeaderDrawn, +}: DrawMathMiniHeaderParams): void { + const { appName, title } = options; + const titleY = 46; + const centerX = canvasWidth / 2; + + // 字体大小除以3 + ctx.font = 'bold 24px "Microsoft Yahei"'; // 64/3 + ctx.fillStyle = '#000'; + ctx.textAlign = 'center'; + ctx.fillText(appName + ' ' + title, centerX, titleY); + + // 调用回调函数,传递除以3后的currentY + if (onHeaderDrawn) { + onHeaderDrawn(64); // 约66.67 + } +} diff --git a/miniprogram/mathPages/service/numberColorDraw.ts b/miniprogram/mathPages/service/numberColorDraw.ts new file mode 100644 index 0000000..58b41be --- /dev/null +++ b/miniprogram/mathPages/service/numberColorDraw.ts @@ -0,0 +1,76 @@ +import { BaseMathDrawService } from './baseMathDraw'; +import { drawNumberPreview } from './numberPreviewDraw'; +import { drawNumberContent } from './numberContentDraw'; +import { drawNumberWriteContent } from './numberWriteDraw'; + +/** + * 数字涂色绘制服务 + * 组合使用基础绘制服务、预览区域绘制服务和内容区域绘制服务 + */ +class NumberColorDraw extends BaseMathDrawService { + selectedNumber: number; + functionId: string; // 功能ID,用于判断绘制类型 + + constructor( + canvas: Canvas, + ctx: RenderingContext, + options?: Record, + ) { + super(canvas, ctx, options); + this.selectedNumber = 0; + this.functionId = options?.functionId || 'number-find'; + } + + async draw(selectedNumber: number) { + if (selectedNumber <= 0 || selectedNumber > 10) { + return; + } + + this.setPrintConfig(); + this.selectedNumber = selectedNumber; + this.clear(); + this.setPaper(); + + // 绘制Header + if (this.headerType !== 'minimal') { + await this.drawHeader(); + } else { + this.drawMiniHeader(); + } + + // 绘制预览区域 + this.drawDivider(); + await drawNumberPreview({ + canvas: this.canvas, + ctx: this.ctx, + selectedNumber: this.selectedNumber, + canvasWidth: this.canvasWidth, + startY: this.currentY, + onDrawn: (currentY) => { + this.currentY = currentY; + }, + }); + + // 绘制内容区域(根据 functionId 选择不同的绘制方法) + this.drawDivider(); + if (this.functionId === 'number-write') { + // 书写类型:绘制书写行 + drawNumberWriteContent({ + ctx: this.ctx, + selectedNumber: this.selectedNumber, + canvasWidth: this.canvasWidth, + startY: this.currentY, + }); + } else { + // 默认类型(number-find):绘制数字涂色内容 + drawNumberContent({ + ctx: this.ctx, + selectedNumber: this.selectedNumber, + canvasWidth: this.canvasWidth, + startY: this.currentY, + }); + } + } +} + +export default NumberColorDraw; diff --git a/miniprogram/mathPages/service/numberContentDraw.ts b/miniprogram/mathPages/service/numberContentDraw.ts new file mode 100644 index 0000000..f188706 --- /dev/null +++ b/miniprogram/mathPages/service/numberContentDraw.ts @@ -0,0 +1,78 @@ +/** + * 绘制内容区域的参数接口 + */ +interface DrawNumberContentParams { + ctx: RenderingContext; + selectedNumber: number; + canvasWidth: number; // 逻辑像素宽度(已除以3) + startY: number; // 起始Y坐标 +} + +/** + * 绘制数字涂色内容区域服务 + * 随机绘制1-10的数字,尺寸除以3 + */ +export function drawNumberContent({ + ctx, + selectedNumber, + canvasWidth, + startY, +}: DrawNumberContentParams): void { + const rows = 6; + const radius = 26; // 约26.67 + const fontSize = 24; // 24 + + const startYPos = startY + 10 + radius; // 约47.33 + const startX1 = 100 + radius; // 约112.22 + const startX2 = 60 + radius; // 约75.56 + const spaceWidthFirst = (canvasWidth - startX1 * 2) / (5 - 1); + const spaceWidthSecond = (canvasWidth - startX2 * 2) / (6 - 1); + const spaceHeight = 18; // 18 + + ctx.moveTo(startX1, startYPos); + for (let i = 0; i < rows; i++) { + const cols = i % 2 === 0 ? 5 : 6; + + for (let j = 0; j < cols; j++) { + const y = startYPos + i * (spaceHeight + radius * 2); + const x = + i % 2 === 0 + ? startX1 + j * spaceWidthFirst + : startX2 + j * spaceWidthSecond; + + // 随机生成1-10的数字,但确保包含选中的数字 + let number: number; + if (i === 0 && j === 0) { + // 第一个位置固定为选中的数字 + number = selectedNumber; + } else { + // 其他位置随机,但增加选中数字出现的概率 + const random = Math.random(); + if (random < 0.3) { + // 30%概率是选中的数字 + number = selectedNumber; + } else { + // 70%概率是其他随机数字 + number = Math.floor(Math.random() * 10) + 1; + } + } + + // 绘制圆形背景(线宽除以3) + ctx.fillStyle = '#fff'; + ctx.strokeStyle = '#000'; + ctx.lineWidth = 1; // 约1.33 + ctx.beginPath(); + ctx.arc(x, y, radius, 0, Math.PI * 2); + ctx.fill(); + ctx.stroke(); + ctx.closePath(); + + // 绘制数字(字体大小除以3) + ctx.fillStyle = '#333'; + ctx.font = `bold ${fontSize}px "Microsoft Yahei"`; + ctx.textBaseline = 'middle'; + ctx.textAlign = 'center'; + ctx.fillText(String(number), x, y, radius * 2); + } + } +} diff --git a/miniprogram/mathPages/service/numberPreviewDraw.ts b/miniprogram/mathPages/service/numberPreviewDraw.ts new file mode 100644 index 0000000..db5c4c9 --- /dev/null +++ b/miniprogram/mathPages/service/numberPreviewDraw.ts @@ -0,0 +1,138 @@ +import { getImage } from '../../utils/index'; + +/** + * 数字到英文单词的映射 + */ +const NUMBER_WORDS: Record = { + 1: 'one', + 2: 'two', + 3: 'three', + 4: 'four', + 5: 'five', + 6: 'six', + 7: 'seven', + 8: 'eight', + 9: 'nine', + 10: 'ten', +}; + +const NUMBER_COLORS: Record = { + 1: '#9FC558', + 2: '#CDB984', + 3: '#B393B8', + 4: '#ED7E97', + 5: '#53B5B9', + 6: '#B3B3B3', + 7: '#EE8B7A', + 8: '#F6C644', + 9: '#99C1F4', + 10: '#F5D25C', +}; + +/** + * 绘制预览区域的参数接口 + */ +interface DrawNumberPreviewParams { + canvas: WechatMiniprogram.Canvas; + ctx: RenderingContext; + selectedNumber: number; + canvasWidth: number; // 逻辑像素宽度(已除以3) + startY: number; // 起始Y坐标 + onDrawn?: (currentY: number) => void; // 绘制完成后的回调 +} + +/** + * 绘制数字预览区域服务 + * 左侧:animal-number 图片 + * 右侧:两个框,第一个框是finger图片,第二个框是英文单词 + * 所有尺寸除以3 + */ +export async function drawNumberPreview({ + canvas, + ctx, + selectedNumber, + canvasWidth, + startY, + onDrawn, +}: DrawNumberPreviewParams): Promise { + // 左侧 animal-number 图片位置 + const animalImageWidth = 360; + const animalImageHeight = 236; + const leftMargin = 35; + const animalImageX = leftMargin; + const animalImageY = startY + 10; + + // 加载并绘制 animal-number 图片 + try { + const animalImagePath = `/mathPages/assets/animal-number/animal-number-${selectedNumber}.png`; + const animalImage = await getImage(canvas, animalImagePath); + ctx.drawImage( + animalImage, + animalImageX, + animalImageY, + animalImageWidth, + animalImageHeight, + ); + } catch (error) { + console.error('加载animal-number图片失败:', error); + } + + // 右侧两个框的位置(逻辑像素,除以3) + const boxWidth = 130; + const boxHeight = 100; + const rightMargin = 35; + const boxSpacing = 30; + const boxX = canvasWidth - rightMargin - boxWidth; + + // 第一个框:finger 图片 + const fingerBoxY = animalImageY; + ctx.strokeStyle = '#000'; + ctx.lineWidth = 1; + ctx.strokeRect(boxX, fingerBoxY, boxWidth, boxHeight); + + try { + const fingerImagePath = `/mathPages/assets/finger/finger-${selectedNumber}.png`; + const fingerImage = await getImage(canvas, fingerImagePath); + // 计算图片在框内的位置(居中显示) + const imagePadding = 10; + const imageWidth = boxWidth - imagePadding * 2; + const imageHeight = boxHeight - imagePadding * 2; + ctx.drawImage( + fingerImage, + boxX + imagePadding, + fingerBoxY + imagePadding, + imageWidth, + imageHeight, + ); + } catch (error) { + console.error('加载finger图片失败:', error); + } + + // 第二个框:英文单词 + const wordBoxY = fingerBoxY + boxHeight + boxSpacing; + ctx.strokeRect(boxX, wordBoxY, boxWidth, boxHeight); + + // 绘制英文单词(字体大小除以3) + const word = NUMBER_WORDS[selectedNumber] || ''; + const color = NUMBER_COLORS[selectedNumber] || '#000'; + ctx.fillStyle = color; + // 推荐使用系统内常见的圆体或幼圆体字体,更适合儿童视觉风格 + ctx.font = + 'bold 32px "HarmonyOS Sans", "PingFang SC", "YouYuan", "Microsoft Yahei", sans-serif'; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText( + word, + boxX + boxWidth / 2, + wordBoxY + boxHeight / 2, + boxWidth - 20, + ); + + // 更新 currentY 为预览区域底部 + const finalY = + Math.max(animalImageY + animalImageHeight, wordBoxY + boxHeight) + 10; + + if (onDrawn) { + onDrawn(finalY); + } +} diff --git a/miniprogram/mathPages/service/numberWriteDraw.ts b/miniprogram/mathPages/service/numberWriteDraw.ts new file mode 100644 index 0000000..a167266 --- /dev/null +++ b/miniprogram/mathPages/service/numberWriteDraw.ts @@ -0,0 +1,99 @@ +/** + * 绘制书写行内容区域的参数接口 + */ +interface DrawNumberWriteContentParams { + ctx: RenderingContext; + selectedNumber: number; + canvasWidth: number; // 逻辑像素宽度 + startY: number; // 起始Y坐标 +} + +/** + * 绘制数字书写内容区域服务 + * 绘制三条书写行,每条行有三条线(上下实线,中间虚线) + * 第一行和第二行有数字(第一个黑色实线,后续灰色虚线),第三行空白 + */ +export function drawNumberWriteContent({ + ctx, + selectedNumber, + canvasWidth, + startY, +}: DrawNumberWriteContentParams): void { + const lineSpacing = 30; // 行间距(三条线之间的间距) + const rowHeight = lineSpacing * 2; // 每行的高度(两条实线之间的距离) + const rowMargin = 24; // 行与行之间的间距 + const leftMargin = 24; // 左边距 + const rightMargin = 24; // 右边距 + const numberIndent = selectedNumber === 10 ? 12 : 24; // 数字缩进(避免贴边) + const numberSpacing = 90; // 数字之间的间距 + const numberCount = 6; // 每行数字的数量(第一个实线 + 6个虚线) + const fontSize = 76; // 数字字体大小(调整为行高的83%,避免超出上下边线) + + // 计算每行的起始Y坐标 + const rowStartY = startY + 20; // 顶部间距 + + // 绘制三条书写行 + for (let rowIndex = 0; rowIndex < 5; rowIndex++) { + const rowY = rowStartY + rowIndex * (rowHeight + rowMargin); + const topLineY = rowY; + const middleLineY = rowY + lineSpacing; + const bottomLineY = rowY + rowHeight; + + // 绘制上实线(蓝色) + ctx.strokeStyle = '#4A90E2'; // 蓝色 + ctx.lineWidth = 1; + ctx.setLineDash([]); // 实线 + ctx.beginPath(); + ctx.moveTo(leftMargin, topLineY); + ctx.lineTo(canvasWidth - rightMargin, topLineY); + ctx.stroke(); + + // 绘制中间虚线(橙色) + ctx.strokeStyle = '#FF8C42'; // 橙色 + ctx.lineWidth = 1; + ctx.setLineDash([12, 12]); // 虚线模式 + ctx.beginPath(); + ctx.moveTo(leftMargin, middleLineY); + ctx.lineTo(canvasWidth - rightMargin, middleLineY); + ctx.stroke(); + ctx.setLineDash([]); // 恢复实线模式 + + // 绘制下实线(蓝色) + ctx.strokeStyle = '#4A90E2'; // 蓝色 + ctx.lineWidth = 1; + ctx.setLineDash([]); // 实线 + ctx.beginPath(); + ctx.moveTo(leftMargin, bottomLineY); + ctx.lineTo(canvasWidth - rightMargin, bottomLineY); + ctx.stroke(); + + // 第一行和第二行绘制数字 + if (rowIndex < 3) { + const centerY = rowY + lineSpacing; // 数字中心Y坐标(中间虚线位置) + + for (let i = 0; i < numberCount; i++) { + const numberX = leftMargin + numberIndent + i * numberSpacing; + + if (i === 0) { + // 第一个数字:黑色实线 + ctx.fillStyle = '#000000'; + ctx.font = `bold ${fontSize}px "Microsoft Yahei"`; + ctx.textBaseline = 'middle'; + ctx.textAlign = 'left'; + ctx.fillText(String(selectedNumber), numberX, centerY); + } else { + // 后续数字:灰色虚线(使用灰色填充配合透明度模拟虚线效果) + const savedAlpha = ctx.globalAlpha; + ctx.globalAlpha = 0.6; // 设置透明度模拟虚线效果 + ctx.fillStyle = '#999999'; // 灰色 + ctx.font = `${fontSize}px "Microsoft Yahei"`; + ctx.textBaseline = 'middle'; + ctx.textAlign = 'left'; + ctx.fillText(String(selectedNumber), numberX, centerY); + ctx.globalAlpha = savedAlpha; // 恢复透明度 + } + } + } + // 第三行不绘制数字(空白行) + } +} diff --git a/miniprogram/pages/mathIndex/mathIndex.less b/miniprogram/pages/mathIndex/mathIndex.less index 5704ded..1f774cc 100644 --- a/miniprogram/pages/mathIndex/mathIndex.less +++ b/miniprogram/pages/mathIndex/mathIndex.less @@ -161,5 +161,12 @@ page { font-size: 24rpx; color: #666666; line-height: 1.5; - white-space: pre-line; + + view { + margin-bottom: 8rpx; + + &:last-child { + margin-bottom: 0; + } + } } \ No newline at end of file diff --git a/miniprogram/pages/mathIndex/mathIndex.ts b/miniprogram/pages/mathIndex/mathIndex.ts index 823c361..db77ad5 100644 --- a/miniprogram/pages/mathIndex/mathIndex.ts +++ b/miniprogram/pages/mathIndex/mathIndex.ts @@ -1,68 +1,8 @@ +import { MATH_FUNCTION_TYPES } from '../../constants/mathFunctions'; + Page({ data: { - functionList: [ - { - id: 'number-find-color', - page: 'numberColor', - title: '看数字,涂一涂', - desc: '给一个数字,找一找下面相同的数字,涂上颜色', - icon: '🔍', - }, - { - id: 'number-coloring', - title: '数字涂色卡', - desc: '一边写数字、一边学数数,数字和卡通图片一一对应', - icon: '🎨', - }, - { - id: 'counting-matching', - title: '数一数,连一连', - desc: '通过连线配对数字和对应的数量图形', - icon: '🔗', - }, - { - id: 'missing-number', - title: '填上缺少的数字', - desc: '在数字序列中找出并填写缺失的数字', - icon: '❓', - }, - { - id: 'compare', - title: '数一数,比大小', - desc: '通过数数比较两组物品的数量大小', - icon: '⚖️', - }, - { - id: 'counting-select', - title: '数一数,选一选', - desc: '数出物品数量,从多个选项中选择正确答案', - icon: '✓', - }, - { - id: 'counting-fill', - title: '数一数,填一填', - desc: '数出物品数量,填写对应的数字', - icon: '✏️', - }, - { - id: 'addition-5', - title: '5以内加法', - desc: '练习5以内的加法运算,图形化展示', - icon: '➕', - }, - { - id: 'addition-10', - title: '10以内加法', - desc: '练习10以内的加法运算,图形化展示', - icon: '➕', - }, - { - id: 'addition-subtraction-10', - title: '10以内加减法', - desc: '练习10以内的加法和减法混合运算', - icon: '±', - }, - ], + functionList: MATH_FUNCTION_TYPES, }, onLoad() { @@ -89,9 +29,9 @@ Page({ }); } else { wx.showToast({ - title: `即将打开:${functionItem.title}`, + title: `功能开发中,敬请期待`, icon: 'none', - duration: 2000, + duration: 2500, }); } }, diff --git a/miniprogram/pages/mathIndex/mathIndex.wxml b/miniprogram/pages/mathIndex/mathIndex.wxml index e072c78..be7428e 100644 --- a/miniprogram/pages/mathIndex/mathIndex.wxml +++ b/miniprogram/pages/mathIndex/mathIndex.wxml @@ -32,9 +32,10 @@ 使用提示 - 1. 点击上方功能卡片选择要生成的涂鸦卡类型\n 2. - 选择数字范围、图形类型等参数\n 3. 预览生成的涂鸦卡效果\n 4. - 下载A4格式PNG图片,打印后使用 + 1. 点击上方功能卡片选择要生成的涂鸦卡类型 + 2. 选择数字等参数 + 3. 预览生成的涂鸦卡效果 + 4. 下载A4格式PNG图片,打印后使用 diff --git a/miniprogram/service/headerDrawService.ts b/miniprogram/service/headerDrawService.ts index 981c487..a57e203 100644 --- a/miniprogram/service/headerDrawService.ts +++ b/miniprogram/service/headerDrawService.ts @@ -99,6 +99,7 @@ interface DrawMiniHeaderParams { appName: string; title: string; }; + canvasWidth?: number; // 逻辑像素宽度(可选,如果提供则使用,否则从 canvas.width 计算) onHeaderDrawn?: (currentY: number) => void; // 绘制完成后的回调,用于设置 currentY 和绘制分割线 } @@ -109,15 +110,20 @@ export function drawMiniHeader({ canvas, ctx, options, + canvasWidth, onHeaderDrawn, }: DrawMiniHeaderParams): void { const { appName, title } = options; const titleY = 120; + // 如果提供了逻辑宽度,使用它;否则使用 canvas.width(假设 ctx 未 scale) + const centerX = + canvasWidth !== undefined ? canvasWidth / 2 : canvas.width / 2; + ctx.font = 'bold 64px "Microsoft Yahei"'; ctx.fillStyle = '#000'; ctx.textAlign = 'center'; - ctx.fillText(appName + ' ' + title, canvas.width / 2, titleY); + ctx.fillText(appName + ' ' + title, centerX, titleY); // 调用回调函数,让调用者设置 currentY 并绘制分割线 if (onHeaderDrawn) { diff --git a/miniprogram/utils/shareGuide.ts b/miniprogram/utils/shareGuide.ts index f04c1b6..0cbe419 100644 --- a/miniprogram/utils/shareGuide.ts +++ b/miniprogram/utils/shareGuide.ts @@ -62,7 +62,7 @@ export function recordShareSuccess(): void { */ export function shouldShowShareGuide(): boolean { // TODO: 开启分享引导 - // return true; + return false; // 如果今天已经分享过,不需要显示引导 if (hasSharedToday()) { return false; diff --git a/project.private.config.json b/project.private.config.json index e54748e..ca0e6d8 100644 --- a/project.private.config.json +++ b/project.private.config.json @@ -26,7 +26,7 @@ { "name": "mathPages/numberColor/numberColor", "pathName": "mathPages/numberColor/numberColor", - "query": "id=number-find-color", + "query": "id=number-write", "scene": null, "launchMode": "default" },