Files
doodle-mini/miniprogram/core/draw/drawHeader.ts
T
2026-04-14 17:34:05 +08:00

112 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 = 2;
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';
// topy 为文本顶边;勿用 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);
}
}