238 lines
7.7 KiB
TypeScript
238 lines
7.7 KiB
TypeScript
// import { PAPER_SIZE } from './constant';
|
||
import { getMiniCodeImage } from './utils';
|
||
|
||
class TextDrawService {
|
||
canvas: WechatMiniprogram.Canvas;
|
||
ctx: RenderingContext;
|
||
options: Record<string, any>;
|
||
paperSize: PaperSize;
|
||
currentX: number;
|
||
currentY: number;
|
||
|
||
constructor(canvas: Canvas, ctx: RenderingContext, options?: Record<string, any>) {
|
||
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;
|
||
|
||
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;
|