feat:架构代码优化
This commit is contained in:
@@ -1,9 +1,5 @@
|
||||
import { PAPER_SIZE } from '../constants/colors';
|
||||
import { BaseDrawService } from './baseDraw';
|
||||
import { CharacterItem } from '../types/characterType';
|
||||
import {
|
||||
drawHeader as drawHeaderCommon,
|
||||
drawMiniHeader as drawMiniHeaderCommon,
|
||||
} from './headerDrawService';
|
||||
|
||||
/**
|
||||
* 仅支持 M/L/Z 的简单 SVG 路径解析与绘制
|
||||
@@ -197,14 +193,14 @@ function drawTianZiGrid({
|
||||
lineColor = '#e0e0e0',
|
||||
boldColor = '#cccccc',
|
||||
}: DrawTianZiGridParams) {
|
||||
// 外框
|
||||
// 外框(逻辑像素)
|
||||
ctx.strokeStyle = boldColor;
|
||||
ctx.lineWidth = 2;
|
||||
ctx.lineWidth = 1; // 2/3≈1,逻辑像素
|
||||
ctx.strokeRect(x - size / 2, y - size / 2, size, size);
|
||||
|
||||
// 中线
|
||||
// 中线(逻辑像素)
|
||||
ctx.strokeStyle = lineColor;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.lineWidth = 1; // 逻辑像素
|
||||
ctx.beginPath();
|
||||
// 竖线
|
||||
ctx.moveTo(x, y - size / 2);
|
||||
@@ -215,7 +211,7 @@ function drawTianZiGrid({
|
||||
ctx.stroke();
|
||||
ctx.closePath();
|
||||
|
||||
// 对角线(淡)
|
||||
// 对角线(淡,逻辑像素)
|
||||
ctx.strokeStyle = '#eeeeee';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
@@ -227,40 +223,18 @@ function drawTianZiGrid({
|
||||
ctx.closePath();
|
||||
}
|
||||
|
||||
class WordDrawService {
|
||||
headerType: PrintHeader = 'wechat';
|
||||
canvas: WechatMiniprogram.Canvas;
|
||||
ctx: RenderingContext;
|
||||
options: Record<string, any>;
|
||||
paperSize: PaperSize;
|
||||
currentX: number;
|
||||
currentY: number;
|
||||
|
||||
class WordDrawService extends BaseDrawService {
|
||||
constructor(
|
||||
canvas: Canvas,
|
||||
ctx: RenderingContext,
|
||||
options?: Record<string, any>,
|
||||
) {
|
||||
options = options || {};
|
||||
this.canvas = canvas;
|
||||
this.ctx = ctx;
|
||||
this.paperSize = 'A4';
|
||||
this.options = {
|
||||
appName: '涂鸦丫小程序',
|
||||
appHint: '识字|识图|练字|打印',
|
||||
super(canvas, ctx, {
|
||||
title: '田字格 练 字 贴',
|
||||
subTitle: '按笔画临摹练习',
|
||||
...options,
|
||||
};
|
||||
this.currentX = 0;
|
||||
this.currentY = 0;
|
||||
this.setPrintConfig();
|
||||
}
|
||||
|
||||
setPrintConfig() {
|
||||
const printConfig = getApp().getPrintConfig();
|
||||
this.headerType = printConfig.header;
|
||||
this.options.appName = printConfig.appName;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -271,12 +245,14 @@ class WordDrawService {
|
||||
this.clear();
|
||||
this.setPaper();
|
||||
|
||||
// 等待页眉绘制完成,确保 this.currentY 被正确设置
|
||||
// 绘制Header
|
||||
if (this.headerType !== 'minimal') {
|
||||
await this.drawHeader();
|
||||
} else {
|
||||
await this.drawMiniHeader();
|
||||
this.drawMiniHeader();
|
||||
}
|
||||
|
||||
this.drawDivider();
|
||||
this.drawContentEmpty();
|
||||
}
|
||||
|
||||
@@ -301,60 +277,19 @@ class WordDrawService {
|
||||
* 清空内容区域(页眉以下的部分)
|
||||
*/
|
||||
private clearContentArea() {
|
||||
const { ctx, canvas } = this;
|
||||
const { ctx } = this;
|
||||
const contentStartY = this.currentY;
|
||||
|
||||
// 清空页眉以下的所有内容
|
||||
// 清空页眉以下的所有内容(使用逻辑像素)
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.fillRect(
|
||||
0,
|
||||
contentStartY,
|
||||
canvas.width,
|
||||
canvas.height - contentStartY,
|
||||
this.canvasWidth,
|
||||
this.canvasHeight - contentStartY,
|
||||
);
|
||||
}
|
||||
|
||||
async drawHeader() {
|
||||
this.currentX = 80;
|
||||
this.currentY = 80;
|
||||
await drawHeaderCommon({
|
||||
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: () => {
|
||||
// wordDrawService 使用不同的计算方式
|
||||
const titleY = 80;
|
||||
const headerHeight = Math.max(titleY + 64 + 48 + 48) + 0; // 64px字体 + 48px间距 + 48px字体 + 20px边距
|
||||
this.currentY = 80 + headerHeight;
|
||||
this.drawDivider(this.currentY);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
drawMiniHeader() {
|
||||
drawMiniHeaderCommon({
|
||||
canvas: this.canvas,
|
||||
ctx: this.ctx,
|
||||
options: {
|
||||
appName: this.options.appName || '涂鸦丫小程序',
|
||||
title: this.options.title || '田字格 练 字 贴',
|
||||
},
|
||||
onHeaderDrawn: () => {
|
||||
// wordDrawService 使用不同的计算方式
|
||||
const titleY = 120;
|
||||
const miniHeaderHeight = titleY + 64 + 20; // 64px字体 + 20px边距
|
||||
this.currentY = miniHeaderHeight;
|
||||
this.drawDivider(this.currentY);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制正文内容:两阶段绘制 - 先绘制空田字格,再绘制练字内容
|
||||
*/
|
||||
@@ -368,18 +303,18 @@ class WordDrawService {
|
||||
* rowGap(行间距)用于田字格竖直方向(每一行田字格之间的间隔)的初始最小值。它防止行与行的田字格上下贴得太紧,增加一定的可视呼吸空间。之后同样会结合剩余空间动态调整为实际间距 actualRowGap。
|
||||
*/
|
||||
drawContent(characterData: CharacterItem[] | null) {
|
||||
const { canvas, ctx } = this;
|
||||
const { ctx } = this;
|
||||
|
||||
// 布局参数
|
||||
const topGap = 50; // 与页眉分割线的距离
|
||||
const leftMargin = 120;
|
||||
const rightMargin = 120;
|
||||
const bottomMargin = 120;
|
||||
// 布局参数(逻辑像素,原始尺寸除以3)
|
||||
const topGap = 17; // 50/3≈17
|
||||
const leftMargin = 40; // 120/3=40
|
||||
const rightMargin = 40; // 120/3=40
|
||||
const bottomMargin = 40; // 120/3=40
|
||||
const contentTop = this.currentY + topGap;
|
||||
const contentWidth = canvas.width - leftMargin - rightMargin;
|
||||
const contentHeight = canvas.height - contentTop - bottomMargin;
|
||||
const contentWidth = this.canvasWidth - leftMargin - rightMargin;
|
||||
const contentHeight = this.canvasHeight - contentTop - bottomMargin;
|
||||
|
||||
const cellSize = 140;
|
||||
const cellSize = 47; // 140/3≈47
|
||||
// 统一通过 getMaxGridLayout 获取最大行列数
|
||||
const { maxRow, maxCol } = this.getMaxGridLayout();
|
||||
|
||||
@@ -423,20 +358,18 @@ class WordDrawService {
|
||||
* 获取当前页面可绘制田字格的最大行数与列数(与绘制使用同一套计算规则)
|
||||
*/
|
||||
getMaxGridLayout(): { maxRow: number; maxCol: number } {
|
||||
const { canvas } = this;
|
||||
|
||||
// 布局参数需与 drawContent 保持一致
|
||||
const topGap = 50;
|
||||
const leftMargin = 120;
|
||||
const rightMargin = 120;
|
||||
const bottomMargin = 120;
|
||||
// 布局参数需与 drawContent 保持一致(逻辑像素)
|
||||
const topGap = 17; // 50/3≈17
|
||||
const leftMargin = 40; // 120/3=40
|
||||
const rightMargin = 40; // 120/3=40
|
||||
const bottomMargin = 40; // 120/3=40
|
||||
const contentTop = this.currentY + topGap;
|
||||
const contentWidth = canvas.width - leftMargin - rightMargin;
|
||||
const contentHeight = canvas.height - contentTop - bottomMargin;
|
||||
const contentWidth = this.canvasWidth - leftMargin - rightMargin;
|
||||
const contentHeight = this.canvasHeight - contentTop - bottomMargin;
|
||||
|
||||
const cellSize = 140;
|
||||
const minGap = 24;
|
||||
const rowGap = 36;
|
||||
const cellSize = 47; // 140/3≈47
|
||||
const minGap = 8; // 24/3=8
|
||||
const rowGap = 12; // 36/3=12
|
||||
|
||||
const maxCol = Math.max(
|
||||
1,
|
||||
@@ -596,7 +529,7 @@ class WordDrawService {
|
||||
uptoInclusive: strokes.length - 1,
|
||||
fillStyle: 'rgb(0,0,0)', // 黑色填充
|
||||
strokeStyle: 'rgb(0,0,0)', // 黑色描边
|
||||
lineWidth: 4, // 较粗的线条
|
||||
lineWidth: 1, // 较粗的线条(4/3≈1,逻辑像素)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -631,7 +564,7 @@ class WordDrawService {
|
||||
|
||||
// console.log(`练习格 [${rowIndex}, ${columnIndex}] 坐标: (${x}, ${y}), 笔画: ${strokeIndex + 1}/${strokes.length}`);
|
||||
|
||||
// 绘制到指定笔画的汉字(红色,中等粗细)
|
||||
// 绘制到指定笔画的汉字(灰色,中等粗细)
|
||||
drawStrokes({
|
||||
ctx,
|
||||
strokes,
|
||||
@@ -641,38 +574,13 @@ class WordDrawService {
|
||||
uptoInclusive: strokeIndex,
|
||||
fillStyle: '#ccc',
|
||||
strokeStyle: '#ccc',
|
||||
lineWidth: 3, // 中等粗细
|
||||
lineWidth: 1, // 中等粗细(3/3=1,逻辑像素)
|
||||
});
|
||||
}
|
||||
|
||||
drawDivider(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();
|
||||
let { width, height } = PAPER_SIZE[this.paperSize];
|
||||
width = width * dpr;
|
||||
height = height * dpr;
|
||||
|
||||
canvas.width = width;
|
||||
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);
|
||||
// drawDivider 已在基类中实现,此方法保留以保持兼容
|
||||
drawDivider(linY?: number) {
|
||||
super.drawDivider();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user