fix(cover): 封面主副标题位置固定化

- 主标题固定 top=200,副标题固定 top=380,不再根据封面形象高度和文字行数动态计算
- 清理未使用的 avatarTop、hasAvatar、mainTitleHeight、subtitleHeight 变量
- 补全 renderCover useCallback 依赖数组(增加 loadAvatarImage)
This commit is contained in:
小鱼开发
2026-05-26 18:54:42 +08:00
parent 9df8572512
commit 9ca07ff571
+8 -29
View File
@@ -69,7 +69,7 @@ const TEMPLATES: Record<CoverTemplate, TemplateDef> = {
mainTitle: {
fontSize: 144,
fill: '#FFD700',
top: 480, // 1920 * 0.25
top: 200,
fontWeight: 'bold',
shadow: new Shadow({
color: 'rgba(0,0,0,0.9)',
@@ -81,7 +81,7 @@ const TEMPLATES: Record<CoverTemplate, TemplateDef> = {
subtitle: {
fontSize: 72,
fill: '#FF8C00',
top: 1575, // 约 82% 处
top: 380,
shadow: new Shadow({
color: 'rgba(0,0,0,0.85)',
blur: 12,
@@ -291,22 +291,17 @@ export function useCoverFabric() {
}
// 2. 封面形象(叠加在背景之上)
let avatarTop = CANVAS_HEIGHT;
let hasAvatar = false;
if (config.avatarImage) {
try {
const scaledHeight = await loadAvatarImage(canvas, config.avatarImage);
avatarTop = CANVAS_HEIGHT - scaledHeight;
hasAvatar = true;
await loadAvatarImage(canvas, config.avatarImage);
} catch (err) {
// 封面形象加载失败不影响主流程,但文字位置需要回退到固定布局
console.warn('[useCoverFabric] 封面形象加载失败:', err);
}
}
const template = TEMPLATES[config.template];
// 预计算主副标题行数和高度,用于动态定位
// 预计算主副标题行数
const mainTitleLines = config.mainTitle.trim()
? wrapTextByWidth(config.mainTitle.trim(), CANVAS_WIDTH - 120, template.mainTitle.fontSize).slice(0, 2)
: [];
@@ -316,26 +311,10 @@ export function useCoverFabric() {
const mainTitleLineHeight = template.mainTitle.fontSize * 1.2;
const subtitleLineHeight = template.subtitle.fontSize * 1.5;
const mainTitleHeight = mainTitleLines.length * mainTitleLineHeight;
const subtitleHeight = subtitleLines.length * subtitleLineHeight;
// 计算文字位置
let subtitleTop: number;
let mainTitleTop: number;
if (hasAvatar) {
// 有封面形象:从人物头顶往上堆叠
const gapAvatarToSub = 50; // 人物与副标题间距
const gapSubToMain = 24; // 副标题与主标题间距
const subtitleBottom = avatarTop - gapAvatarToSub;
subtitleTop = subtitleBottom - subtitleHeight;
const mainTitleBottom = subtitleTop - gapSubToMain;
mainTitleTop = mainTitleBottom - mainTitleHeight;
} else {
// 无封面形象:使用模板固定位置(避免文字堆在画布底部)
mainTitleTop = template.mainTitle.top;
subtitleTop = template.subtitle.top;
}
// 文字位置固定,不再根据封面形象高度和文字行数动态计算
const mainTitleTop = template.mainTitle.top;
const subtitleTop = template.subtitle.top;
// 3. 主标题(放在人物上方最外侧)
if (mainTitleLines.length > 0) {
@@ -384,7 +363,7 @@ export function useCoverFabric() {
canvas.renderAll();
},
[loadBackground]
[loadBackground, loadAvatarImage]
);
// 导出 PNG