diff --git a/miniprogram/canvasService/textDrawService.ts b/miniprogram/canvasService/textDrawService.ts index 775372d..1a69df2 100644 --- a/miniprogram/canvasService/textDrawService.ts +++ b/miniprogram/canvasService/textDrawService.ts @@ -1,4 +1,5 @@ import { PAPER_SIZE } from './constant'; +import { getMiniCodeImagePath } from './utils'; class TextDrawService { canvas: WechatMiniprogram.Canvas; @@ -33,11 +34,6 @@ class TextDrawService { } drawHeader() { - const { canvas, ctx } = this; - const { appName, appHint, title, subTitle } = this.options; - } - - drawHeader2() { const { canvas, ctx } = this; const { title } = this.options; diff --git a/miniprogram/canvasService/textDrawServiceV2.ts b/miniprogram/canvasService/textDrawServiceV2.ts new file mode 100644 index 0000000..988ff27 --- /dev/null +++ b/miniprogram/canvasService/textDrawServiceV2.ts @@ -0,0 +1,239 @@ +// import { PAPER_SIZE } from './constant'; +import { getMiniCodeImage } from './utils'; + +class TextDrawService { + canvas: WechatMiniprogram.Canvas; + ctx: RenderingContext; + options: Record; + paperSize: PaperSize; + currentX: number; + currentY: number; + + constructor(canvas: Canvas, ctx: RenderingContext, options?: Record) { + this.canvas = canvas; + this.ctx = ctx; + this.paperSize = 'A4'; + this.options = { + appName: '涂鸦呀', + appHint: '涂色|识字|画画|认知', + title: '找一找 涂 色', + subTitle: '把相同的文字涂上相同的颜色', + radius: 36, + colors: ['#2196F3', '#FFEB3B', '#FF9800', '#F44336', '#F44336'], + characters: ['鱼', '鸟', '猫', '狗', '牛'], + ...options, + }; + this.currentX = 0; + this.currentY = 0; + } + + draw() { + this.setPaper(); + this.setPaper3(); + this.drawHeader(); + // this.drawLegend(); + } + + async drawHeader() { + const { canvas, ctx } = this; + const { appName, appHint, title, subTitle } = this.options; + + this.currentX = 60; + this.currentY = 60; + const titleX = this.currentX + 140 + 14; + const titleY = 87; + const image = await getMiniCodeImage(canvas); + ctx.drawImage(image, 60, 60, 140, 140); + + ctx.font = 'bold 36px "Microsoft Yahei"'; + ctx.fillStyle = '#000'; + ctx.textAlign = 'left'; + ctx.textBaseline = 'top'; + + ctx.fillText(appName, titleX, titleY); + + ctx.font = '24px "Microsoft Yahei"'; + ctx.fillStyle = '#666'; + ctx.fillText(appHint, titleX, 163); + + // 绘制分割线 + ctx.strokeStyle = '#888'; + ctx.lineWidth = 2; + ctx.beginPath(); + ctx.moveTo(483, 70); + ctx.lineTo(483, 70 + 140); + ctx.stroke(); + + ctx.font = 'bold 36px "Microsoft Yahei"'; + ctx.fillStyle = '#000'; + ctx.fillText(title, 538, titleY); + + ctx.font = '24px "Microsoft Yahei"'; + ctx.fillStyle = '#666'; + ctx.fillText(subTitle, 538, 163); + + this.drawLegend(); + } + + /** 绘制示例 + * 矩形: x、y为左上角 + * 圆形:x、y为圆心 + * 文字:x textAlign 为 start,文本左边缘对齐 + * y textBaseline 为 alphabetic,y 对应字母基线(类似左下角) + * + * */ + drawLegend() { + const { canvas, ctx, options } = this; + const { colors, characters, radius } = options; + const rectWidth = 100; + const rectHeight = 48; + const startX = 978; + const startY = 60 + radius; // 设置起始Y坐标 + const len = characters.length || 4; + const canvasWidth = canvas.width; + /** 计算每个圆之间的间距 俩个60,一个是页面右侧边距,另一个是圆离右边距地边距*/ + const spaceWidth = (canvasWidth - startX - 60 - 60 - radius * (len - 1)) / (len - 1); + + ctx.moveTo(startX, startY); + colors.forEach((color: string, index: number) => { + const x = startX + index * (spaceWidth + radius); + const y = startY; // 计算圆的Y坐标 + + // 绘制圆 + ctx.strokeStyle = '#333'; + ctx.fillStyle = color; + ctx.lineWidth = 2; + ctx.beginPath(); + ctx.arc(x, y, radius, 0, Math.PI * 2); + ctx.fill(); + ctx.stroke(); + ctx.closePath(); + + // 绘制长方形 + ctx.fillStyle = '#fff'; // 长方形背景色 + ctx.strokeStyle = '#333'; + ctx.lineWidth = 2; + const rectangleX = x - rectWidth / 2; // 从圆形移动一半的长方形的长 + const rectangleY = y + radius + 18; // 从圆形下移一个半径,再加上18的间距 + ctx.strokeRect(rectangleX, rectangleY, rectWidth, rectHeight); // 绘制长方形 + + // 绘制字符 + ctx.fillStyle = '#333'; + ctx.font = 'bold 24px "Microsoft Yahei"'; + ctx.textBaseline = 'top'; + ctx.fillText(characters[index], rectangleX + 38, 163); + }); + + this.currentY = 220; // 计算分割线的Y坐标,距离示例图20px + this.drawLine(this.currentY); + } + + drawLine(linY: number) { + const { canvas, ctx } = this; + + ctx.strokeStyle = '#333'; + ctx.lineWidth = 2; + ctx.beginPath(); + ctx.moveTo(20, linY); + ctx.lineTo(canvas.width - 20, linY); + ctx.stroke(); + } + + setPaper() { + const { ctx, canvas } = this; + const { pixelRatio: dpr } = wx.getWindowInfo(); + const { width, height } = { width: 595 * dpr, height: 842 * dpr }; + + canvas.width = width; + canvas.height = height; + + console.log('width---:', width); + console.log('height---:', height); + this.clear(); + ctx.fillStyle = '#fff'; // 设置背景色为白色 + ctx.fillRect(0, 0, width, height); + } + + setPaper3() { + const { ctx, canvas } = this; + const { pixelRatio: dpr } = wx.getWindowInfo(); + // @ts-ignore + const winWidth = canvas._width; + // @ts-ignore + const winHeight = canvas._height; // 容器逻辑尺寸 + + // 计算适配后的物理尺寸 + const targetWidth = winWidth * dpr; // 宽度100%适配容器 + const aspectRatio = 842 / 595; // 原图宽高比(示例为A4纸比例) + let targetHeight = targetWidth * aspectRatio; // 按比例计算高度 + + // 判断是否需要裁剪高度 + if (targetHeight > winHeight * dpr) { + targetHeight = winHeight * dpr; // 若超出容器高度则强制裁剪 + } + + // 设置 Canvas 物理像素 + canvas.width = targetWidth; + canvas.height = targetHeight; + + console.log('targetWidth---:', targetWidth); + console.log('targetHeight---:', targetHeight); + + this.clear(); + ctx.fillStyle = '#fff'; // 设置背景色为白色 + ctx.fillRect(0, 0, targetWidth, targetHeight); + } + + setPaper2() { + const { canvas, ctx } = this; + const { pixelRatio: dpr } = wx.getWindowInfo(); + const { width, height } = { width: 595 * dpr, height: 842 * dpr }; + // @ts-ignore + const winWidth = canvas._width; + // @ts-ignore + const winHeight = canvas._height; + + const canvasAspect = width / height; // Canvas 内容的宽高比 + const containerAspect = winHeight / winWidth; // 容器的宽高比 + + // 选择缩放比例较小的方向(确保内容完全显示) + let scaleRatio = + containerAspect > canvasAspect + ? winWidth / width // 以宽度为基准 + : winHeight / height; // 以高度为基准 + + console.log('scaleRatio-----:', scaleRatio); + + const scaledWidth = width * scaleRatio; + const scaledHeight = height * scaleRatio; + + // 避免超过小程序画布最大限制(4096) + if (scaledWidth > 4096 || scaledHeight > 4096) { + scaleRatio *= Math.min(4096 / scaledWidth, 4096 / scaledHeight); + } + + console.log('scaledWidth-----:', scaledWidth); + console.log('scaledHeight-----:', scaledHeight); + + canvas.width = scaledWidth; + canvas.height = scaledHeight; + + ctx.translate((winWidth * dpr) / 2, (winHeight * dpr) / 2); + ctx.scale(scaleRatio * dpr, scaleRatio * dpr); + ctx.translate(-width / 2, -height / 2); // 将内容原点移至中心 + + // this.canvas.width = width; + // this.canvas.height = height; + + this.clear(); + ctx.fillStyle = '#fff'; // 设置背景色为白色 + ctx.fillRect(0, 0, width, height); + } + + clear() { + const canvas = this.canvas; + this.ctx.clearRect(0, 0, canvas.width, canvas.height); + } +} + +export default TextDrawService; diff --git a/miniprogram/canvasService/utils.ts b/miniprogram/canvasService/utils.ts index e05a9d7..c57f8ae 100644 --- a/miniprogram/canvasService/utils.ts +++ b/miniprogram/canvasService/utils.ts @@ -16,22 +16,19 @@ export function setCanvasSize(canvas: Canvas, paperSize: PaperSize) { return canvas; } -export async function getMiniCodeImagePath() { - return getImagePath('/assets/imgs/mini-code.jpg'); +export async function getMiniCodeImage(canvas: Canvas) { + return getImage(canvas, '/assets/imgs/mini-code.jpg'); } -export async function getImagePath(path: string) { - return new Promise((resolve) => { - // 如果是网络图片,需配置downloadFile域名 - wx.getImageInfo({ - src: path, // 本地图片路径 - success: (res) => { - resolve(res.path); - }, - fail: (err) => { - console.error('图片加载失败:', err); - resolve(''); // 可设置默认占位图 - }, - }); +export async function getImage(canvas: Canvas, path: string) { + return new Promise((resolve, reject) => { + const image = canvas.createImage(); + image.onload = () => { + resolve(image); + }; + image.onerror = () => { + reject('图片加载异常'); + }; + image.src = path; }); } diff --git a/miniprogram/demoPages/textPaint2/textPaint.ts b/miniprogram/demoPages/textPaint2/textPaint.ts index 8dc002d..f7bf0f7 100644 --- a/miniprogram/demoPages/textPaint2/textPaint.ts +++ b/miniprogram/demoPages/textPaint2/textPaint.ts @@ -1,4 +1,5 @@ -import TextDrawService from '../../canvasService/textDrawService'; +// import TextDrawService from '../../canvasService/textDrawService'; +import TextDrawServiceV2 from '../../canvasService/textDrawServiceV2'; Page({ canvas: null as Canvas | null, @@ -45,12 +46,12 @@ Page({ .exec((res) => { const canvas = res[0].node; const ctx = canvas.getContext('2d'); - - const textDrawService = new TextDrawService(canvas, ctx); - textDrawService.draw(); - this.canvas = canvas; this.ctx = ctx; + + const textDrawService = new TextDrawServiceV2(canvas, ctx); + textDrawService.draw(); + // this.setCanvasSize(canvas, ctx); // ctx.fillRect(0, 0, 2480, 3508); // this.drawGameBoard(ctx);