feat: 文字涂色

This commit is contained in:
2025-03-30 19:59:59 +08:00
parent 2d686a9c01
commit c00c45a9be
8 changed files with 324 additions and 25 deletions
+4 -2
View File
@@ -1,7 +1,9 @@
const PAPER_SIZE = {
A4: {
width: 2480,
height: 3508,
// width: 2480,
// height: 3508,
width: 595,
height: 842,
},
A3: {
width: 3508,
@@ -29,7 +29,7 @@ class TextDrawService {
draw() {
this.setPaper();
this.setPaper3();
// this.setPaper3();
this.drawHeader();
// this.drawLegend();
}
@@ -0,0 +1,220 @@
// import { PAPER_SIZE } from './constant';
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: '把相同的文字涂上相同的颜色',
colors: ['#FF0000', '#FDAF1A', '#0057FC', '#09FF00', '#8D00FF'],
characters: ['文', '升', '国', '舟', '丹'],
...options,
};
this.currentX = 0;
this.currentY = 0;
}
draw() {
this.setPaper();
this.drawHeader();
this.drawLegend();
this.drawContent();
}
async drawHeader() {
const { canvas, ctx } = this;
const { appName, appHint, title, subTitle } = this.options;
this.currentX = 80;
this.currentY = 80;
const titleX = this.currentX + 200 + 48;
const titleY = 80;
const image = await getMiniCodeImage(canvas);
ctx.drawImage(image, 80, 80, 200, 200);
ctx.font = 'bold 64px "Microsoft Yahei"';
ctx.fillStyle = '#000';
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
ctx.fillText(appName, titleX, titleY);
ctx.font = '48px "Microsoft Yahei"';
ctx.fillStyle = '#666';
ctx.fillText(appHint, titleX, 186);
// 绘制分割线
// ctx.strokeStyle = '#888';
// ctx.lineWidth = 2;
// ctx.beginPath();
// ctx.moveTo(483, 70);
// ctx.lineTo(483, 70 + 140);
// ctx.stroke();
ctx.font = 'bold 64px "Microsoft Yahei"';
ctx.fillStyle = '#000';
ctx.fillText(title, 1015, titleY);
ctx.font = '48px "Microsoft Yahei"';
ctx.fillStyle = '#666';
ctx.fillText(subTitle, 1015, 186);
this.currentY = 304;
this.drawLine(this.currentY);
}
/** 绘制示例
* 矩形: x、y为左上角
* 圆形:x、y为圆心
* 文字:x textAlign 为 start,文本左边缘对齐
* y textBaseline 为 alphabeticy 对应字母基线(类似左下角)
*
* */
drawLegend() {
const { canvas, ctx, options } = this;
const { colors, characters } = options;
const radius = 65;
const rectWidth = 180;
const rectHeight = 80;
const startX = 260 + radius; // 圆形的X坐标是圆心
const startY = 304 + 26 + radius; // 圆形的Y坐标是圆心
const len = characters.length || 4;
const canvasWidth = canvas.width;
/** 计算每个圆之间的间距 俩个60,一个是页面右侧边距,另一个是圆离右边距地边距*/
const spaceWidth = (canvasWidth - startX * 2) / (len - 1);
ctx.moveTo(startX, startY);
colors.forEach((color: string, index: number) => {
const x = startX + index * spaceWidth;
const y = startY; // 计算圆的Y坐标
// 绘制圆
ctx.strokeStyle = '#000';
ctx.fillStyle = color;
ctx.lineWidth = 4;
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
ctx.closePath();
// 绘制长方形
ctx.fillStyle = '#fff'; // 长方形背景色
ctx.strokeStyle = '#000';
ctx.lineWidth = 4;
const rectangleX = x - rectWidth / 2; // 从圆形移动一半的长方形的长
const rectangleY = y + radius + 43; // 从圆形下移一个半径,再加上43的间距
ctx.strokeRect(rectangleX, rectangleY, rectWidth, rectHeight); // 绘制长方形
// 绘制字符
ctx.fillStyle = '#333';
ctx.font = 'bold 48px "Microsoft Yahei"';
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
ctx.fillText(
characters[index],
rectangleX + rectWidth / 2,
rectangleY + rectHeight / 2,
rectWidth,
);
});
this.currentY = 612; // 计算分割线的Y坐标,距离示例图20px
this.drawLine(this.currentY);
}
drawContent() {
const { canvas, ctx, options } = this;
const { characters } = options;
const len = characters.length;
const rows = 8;
const radius = 80;
const fontSize = 72;
const startY = this.currentY + 62 + radius;
const startX1 = 310 + radius;
const startX2 = 200 + radius;
const canvasWidth = canvas.width;
const spaceWidthFrist = (canvasWidth - startX1 * 2) / (5 - 1);
const spaceWidthSecond = (canvasWidth - startX2 * 2) / (6 - 1);
const spaceHeight = 54;
ctx.moveTo(startX1, startY);
for (let i = 0; i < rows; i++) {
const cols = i % 2 === 0 ? 5 : 6;
for (let j = 0; j < cols; j++) {
const y = startY + i * (spaceHeight + radius * 2);
const x =
i % 2 === 0 ? startX1 + j * spaceWidthFrist : startX2 + j * spaceWidthSecond;
const character = characters[Math.floor(Math.random() * len)];
ctx.fillStyle = '#fff';
ctx.strokeStyle = '#000';
ctx.lineWidth = 4;
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fill();
ctx.stroke();
ctx.closePath();
ctx.fillStyle = '#333';
ctx.font = `${fontSize}px "Microsoft Yahei"`;
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
ctx.fillText(character, x, y, radius * 2);
}
}
}
drawLine(linY: number) {
const { canvas, ctx } = this;
ctx.strokeStyle = '#000';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(80, linY);
ctx.lineTo(canvas.width - 80, linY);
ctx.stroke();
}
setPaper() {
const { ctx, canvas } = this;
const { pixelRatio: dpr } = wx.getWindowInfo();
// const { width, height } = { width: 595 * dpr, height: 842 * dpr };
let { width, height } = PAPER_SIZE[this.paperSize];
width = width * dpr;
height = height * 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);
}
clear() {
const canvas = this.canvas;
this.ctx.clearRect(0, 0, canvas.width, canvas.height);
}
}
export default TextDrawService;