fix(cover): 封面主副标题位置固定化
- 主标题固定 top=200,副标题固定 top=380,不再根据封面形象高度和文字行数动态计算 - 清理未使用的 avatarTop、hasAvatar、mainTitleHeight、subtitleHeight 变量 - 补全 renderCover useCallback 依赖数组(增加 loadAvatarImage)
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user