feat: 绘制基础类重构
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import { getMiniCodeImage } from '../../utils/index';
|
||||
|
||||
/**
|
||||
* 统一打印纸页眉(与 UI 稿一致:左上 Logo、居中主标题、姓名/日期/得分、底部分割线)
|
||||
*/
|
||||
interface DrawBaseHeaderParams {
|
||||
canvas: WechatMiniprogram.Canvas;
|
||||
ctx: RenderingContext;
|
||||
canvasWidth: number;
|
||||
options: {
|
||||
/** 练习纸主标题,如「数一数,连一连」 */
|
||||
title: string;
|
||||
};
|
||||
onHeaderDrawn?: (currentY: number) => void;
|
||||
}
|
||||
|
||||
const MARGIN_X = 24;
|
||||
const LOGO_SIZE = 68;
|
||||
const LOGO_X = MARGIN_X;
|
||||
const LOGO_Y = 14;
|
||||
const TITLE_FONT = 'bold 20px "Microsoft Yahei"';
|
||||
const META_FONT = '14px "Microsoft Yahei"';
|
||||
const META_FONT_PX = 12;
|
||||
const META_UNDERLINE_GAP = 3;
|
||||
const TITLE_COLOR = '#322E25';
|
||||
const LINE_COLOR = 'rgba(50, 46, 37, 0.4)';
|
||||
const LINE_WIDTH = 3;
|
||||
const META_COLOR = '#7C766A';
|
||||
const META_ROW_MARGIN_X = 130;
|
||||
|
||||
function drawMetaField(
|
||||
ctx: RenderingContext,
|
||||
label: string,
|
||||
x: number,
|
||||
y: number,
|
||||
underlineRight: number,
|
||||
) {
|
||||
ctx.font = META_FONT;
|
||||
ctx.fillStyle = META_COLOR;
|
||||
ctx.textAlign = 'left';
|
||||
ctx.textBaseline = 'top';
|
||||
ctx.fillText(label, x, y);
|
||||
const metrics = ctx.measureText(label);
|
||||
const labelW = metrics.width;
|
||||
// textBaseline=top 时 y 是字顶,不是垂直中心;下划线应从字底开始(约一行字高,与 META_FONT 字号一致)
|
||||
const lineY = y + META_FONT_PX + META_UNDERLINE_GAP;
|
||||
ctx.strokeStyle = '#E5DCC9';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x + labelW + 2, lineY);
|
||||
ctx.lineTo(Math.max(x + labelW + 2, underlineRight), lineY);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
export default async function drawHeader({
|
||||
canvas,
|
||||
ctx,
|
||||
canvasWidth,
|
||||
options,
|
||||
onHeaderDrawn,
|
||||
}: DrawBaseHeaderParams): Promise<void> {
|
||||
const { title } = options;
|
||||
|
||||
const image = await getMiniCodeImage(canvas);
|
||||
ctx.drawImage(image, LOGO_X, LOGO_Y, LOGO_SIZE, LOGO_SIZE);
|
||||
|
||||
ctx.font = TITLE_FONT;
|
||||
ctx.fillStyle = TITLE_COLOR;
|
||||
ctx.textAlign = 'center';
|
||||
// top:y 为文本顶边;勿用 alphabetic,否则 y 是基线,大字会大量画在 y 上方导致裁出纸上沿
|
||||
ctx.textBaseline = 'top';
|
||||
const titleY = 22;
|
||||
ctx.fillText(title, canvasWidth / 2, titleY);
|
||||
|
||||
const metaRowY = 65;
|
||||
const innerLeft = META_ROW_MARGIN_X;
|
||||
const innerRight = canvasWidth - META_ROW_MARGIN_X;
|
||||
const innerW = innerRight - innerLeft;
|
||||
const colW = innerW / 3;
|
||||
|
||||
drawMetaField(ctx, '姓名:', innerLeft + 4, metaRowY, innerLeft + colW - 8);
|
||||
drawMetaField(
|
||||
ctx,
|
||||
'日期:',
|
||||
innerLeft + colW + 4,
|
||||
metaRowY,
|
||||
innerLeft + 2 * colW - 8,
|
||||
);
|
||||
drawMetaField(
|
||||
ctx,
|
||||
'得分:',
|
||||
innerLeft + 2 * colW + 4,
|
||||
metaRowY,
|
||||
innerRight - 4,
|
||||
);
|
||||
|
||||
ctx.save();
|
||||
const separatorY = 96;
|
||||
ctx.strokeStyle = LINE_COLOR;
|
||||
ctx.lineWidth = LINE_WIDTH;
|
||||
ctx.lineCap = 'round';
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(MARGIN_X, separatorY);
|
||||
ctx.lineTo(canvasWidth - MARGIN_X, separatorY);
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
const contentStartY = separatorY + 14;
|
||||
if (onHeaderDrawn) {
|
||||
onHeaderDrawn(contentStartY);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user