177 lines
4.5 KiB
TypeScript
177 lines
4.5 KiB
TypeScript
/**
|
|
* 绘制工具集合(后续可继续扩展其他通用绘制方法)
|
|
*/
|
|
|
|
import {
|
|
ACTIVE_FONT_PROFILE,
|
|
getLetterMetrics,
|
|
type FontProfile,
|
|
} from '../data/fontProfiles';
|
|
|
|
// ── 四线三格统一高度(所有页面共用) ──
|
|
export const FOUR_LINE_GRID_H = 43;
|
|
|
|
// ── 英语字母字体集合 ──
|
|
export const TOY_FONT_LETTER = 'ToyLetterFont';
|
|
|
|
let _fontLoaded = false;
|
|
export function loadLetterFont(): Promise<void> {
|
|
if (_fontLoaded) return Promise.resolve();
|
|
return new Promise((resolve, reject) => {
|
|
wx.loadFontFace({
|
|
family: TOY_FONT_LETTER,
|
|
source: `url("${ACTIVE_FONT_PROFILE.url}")`,
|
|
scopes: ['native'],
|
|
success: () => {
|
|
_fontLoaded = true;
|
|
resolve();
|
|
},
|
|
fail: (err) => {
|
|
console.error('loadFontFace failed', err);
|
|
reject(err);
|
|
},
|
|
});
|
|
});
|
|
}
|
|
|
|
// ── 向后兼容:LetterFontSizes 类型保留,供外部已有调用使用 ──
|
|
|
|
export type LetterFontSizes = {
|
|
/** 字体配置(新机制) */
|
|
_profile: FontProfile;
|
|
/** gridH(用于运行时计算) */
|
|
_gridH: number;
|
|
};
|
|
|
|
/**
|
|
* 根据四线三格总高度,构建 LetterFontSizes。
|
|
* 内部持有 FontProfile 引用,按字母查表计算。
|
|
*/
|
|
export function calcLetterFontSizes(gridH: number): LetterFontSizes {
|
|
return {
|
|
_profile: ACTIVE_FONT_PROFILE,
|
|
_gridH: gridH,
|
|
};
|
|
}
|
|
|
|
/** 根据字母和字体配置,计算对应 fontSize */
|
|
export function getLetterFontSize(
|
|
letter: string,
|
|
sizes: LetterFontSizes,
|
|
): number {
|
|
const metrics = getLetterMetrics(letter, sizes._profile);
|
|
return sizes._gridH * metrics.scale;
|
|
}
|
|
|
|
/** 根据字母和字体配置,计算基线 Y 偏移修正(px) */
|
|
function getLetterBaselineOffset(
|
|
letter: string,
|
|
sizes: LetterFontSizes,
|
|
): number {
|
|
const metrics = getLetterMetrics(letter, sizes._profile);
|
|
return sizes._gridH * metrics.baselineOffset;
|
|
}
|
|
|
|
// ── 向后兼容:导出 DESCENDERS 集合 ──
|
|
export { DESCENDERS } from '../data/fontProfiles';
|
|
|
|
/**
|
|
* 在四线三格中绘制单个字母(基线固定在 y + 2h/3 + baselineOffset)。
|
|
*
|
|
* @param cx 字母水平中心
|
|
* @param gridY 四线三格顶线 Y
|
|
* @param gridH 四线三格总高度
|
|
* @param sizes 预计算的字号(由 calcLetterFontSizes 生成)
|
|
*/
|
|
export function drawLetterInFourLineGrid(
|
|
ctx: RenderingContext,
|
|
letter: string,
|
|
cx: number,
|
|
gridY: number,
|
|
gridH: number,
|
|
sizes: LetterFontSizes,
|
|
options?: {
|
|
fontFamily?: string;
|
|
color?: string;
|
|
bold?: boolean;
|
|
},
|
|
) {
|
|
const fontFamily =
|
|
options?.fontFamily ?? `${TOY_FONT_LETTER}, Roboto, sans-serif`;
|
|
const color = options?.color ?? '#1a1a1a';
|
|
const bold = options?.bold ?? false;
|
|
|
|
const baselineY =
|
|
gridY + (gridH * 2) / 3 + getLetterBaselineOffset(letter, sizes);
|
|
const fontSize = getLetterFontSize(letter, sizes);
|
|
|
|
ctx.save();
|
|
ctx.font = `${bold ? 'bold ' : ''}${fontSize}px ${fontFamily}`;
|
|
ctx.fillStyle = color;
|
|
ctx.textAlign = 'center';
|
|
ctx.textBaseline = 'alphabetic';
|
|
ctx.fillText(letter, cx, baselineY);
|
|
ctx.restore();
|
|
}
|
|
|
|
export type FourLineGridStyle = {
|
|
/** 顶线/底线颜色 */
|
|
ink?: string;
|
|
/** 中间两条虚线颜色 */
|
|
middleInk?: string;
|
|
/** 线宽 */
|
|
lineWidth?: number;
|
|
/** 虚线样式 */
|
|
dash?: number[];
|
|
};
|
|
|
|
/**
|
|
* 四线三格(通用)
|
|
* - 顶/底:实线
|
|
* - 中间两条:虚线
|
|
*/
|
|
export function drawFourLineGrid(
|
|
ctx: RenderingContext,
|
|
x: number,
|
|
y: number,
|
|
w: number,
|
|
h: number,
|
|
style?: FourLineGridStyle,
|
|
) {
|
|
const ink = style?.ink ?? '#322E25';
|
|
const middleInk = style?.middleInk ?? 'rgba(50, 46, 37, 0.3)';
|
|
const lineWidth = style?.lineWidth ?? 1;
|
|
const dash = style?.dash ?? [4, 4];
|
|
|
|
const yTop = y;
|
|
const y1 = y + h / 3;
|
|
const y2 = y + (h * 2) / 3;
|
|
const yBot = y + h;
|
|
|
|
ctx.strokeStyle = ink;
|
|
ctx.lineWidth = lineWidth;
|
|
ctx.setLineDash([]);
|
|
ctx.beginPath();
|
|
ctx.moveTo(x, yTop);
|
|
ctx.lineTo(x + w, yTop);
|
|
ctx.stroke();
|
|
|
|
ctx.strokeStyle = middleInk;
|
|
ctx.setLineDash(dash);
|
|
ctx.beginPath();
|
|
ctx.moveTo(x, y1);
|
|
ctx.lineTo(x + w, y1);
|
|
ctx.stroke();
|
|
ctx.beginPath();
|
|
ctx.moveTo(x, y2);
|
|
ctx.lineTo(x + w, y2);
|
|
ctx.stroke();
|
|
|
|
ctx.strokeStyle = ink;
|
|
ctx.setLineDash([]);
|
|
ctx.beginPath();
|
|
ctx.moveTo(x, yBot);
|
|
ctx.lineTo(x + w, yBot);
|
|
ctx.stroke();
|
|
}
|