显卡分页逻辑以及移动逻辑修复
This commit is contained in:
parent
830f16a9f5
commit
2355147ed5
@ -752,7 +752,7 @@ export default {
|
||||
imageSize: 1, // 32x32
|
||||
imageColor: 0, // 红色(默认)
|
||||
effect: 0,
|
||||
speed: 4,
|
||||
speed: 0,
|
||||
stayTime: 5,
|
||||
hAlign: 1,
|
||||
vAlign: 1,
|
||||
@ -1053,7 +1053,7 @@ export default {
|
||||
imageSize: 1,
|
||||
imageColor: 0, // 红色(默认)
|
||||
effect: 0,
|
||||
speed: 4,
|
||||
speed: 0,
|
||||
stayTime: 5,
|
||||
hAlign: 1,
|
||||
vAlign: 1,
|
||||
@ -1093,7 +1093,7 @@ export default {
|
||||
// 解析动画效果
|
||||
if (item.anim) {
|
||||
zone.effect = item.anim.typ ? item.anim.typ - 1 : 0; // 动画类型需要减1
|
||||
zone.speed = item.anim.spd || 4; // 动画速度
|
||||
zone.speed = item.anim.spd || 0; // 动画速度
|
||||
zone.stayTime = item.anim.pauseT ? this.getStayTimeIndex(item.anim.pauseT) : 5; // 暂停时间索引
|
||||
}
|
||||
}
|
||||
@ -1117,7 +1117,7 @@ export default {
|
||||
imageSize: 1,
|
||||
imageColor: 0, // 红色(默认)
|
||||
effect: 0,
|
||||
speed: 4,
|
||||
speed: 0,
|
||||
stayTime: 5,
|
||||
hAlign: 1,
|
||||
vAlign: 1,
|
||||
@ -2231,7 +2231,7 @@ export default {
|
||||
imageSize: 1,
|
||||
imageColor: 0, // 红色(默认)
|
||||
effect: 0,
|
||||
speed: 4,
|
||||
speed: 0,
|
||||
stayTime: 5,
|
||||
hAlign: 1,
|
||||
vAlign: 1,
|
||||
@ -2275,7 +2275,7 @@ export default {
|
||||
imageSize: 1,
|
||||
imageColor: 0, // 红色(默认)
|
||||
effect: 0,
|
||||
speed: 4,
|
||||
speed: 0,
|
||||
stayTime: 5,
|
||||
hAlign: 1,
|
||||
vAlign: 1,
|
||||
@ -2413,7 +2413,7 @@ export default {
|
||||
|
||||
// 只下发当前节目
|
||||
const programData = {
|
||||
del_prog: 0, // 不删除节目
|
||||
// del_prog: 0, // 不删除节目
|
||||
prog_list: [programObj]
|
||||
};
|
||||
|
||||
@ -2517,7 +2517,7 @@ export default {
|
||||
|
||||
if (zone.playType === 0 && asset.isText) {
|
||||
// 文本类型分区
|
||||
const page = this.addProgramPreviewPage[zIdx] || 0;
|
||||
const page = state && typeof state.currentPage === 'number' ? state.currentPage : 0;
|
||||
const pageLines = asset.pages[page] || [];
|
||||
|
||||
// 设置字体样式
|
||||
@ -2580,7 +2580,17 @@ export default {
|
||||
if (effect === 3 || effect === 4) animOffsetY = state.currentY;
|
||||
}
|
||||
|
||||
ctx.fillText(line, startX + animOffsetX, startY + lineIdx * lineHeight + animOffsetY);
|
||||
// 连续左移效果(无缝循环)
|
||||
if (zone.effect === 5 && state) {
|
||||
let x1 = zoneX + state.currentX;
|
||||
let x2 = x1 + textWidth;
|
||||
// 垂直居中
|
||||
let y = zoneY + (zoneHeight - lineHeight) / 2;
|
||||
ctx.fillText(line, x1, y);
|
||||
ctx.fillText(line, x2, y);
|
||||
} else {
|
||||
ctx.fillText(line, startX + (state ? state.currentX : 0), startY + lineIdx * lineHeight + (state ? state.currentY : 0));
|
||||
}
|
||||
});
|
||||
} else if (zone.playType === 1 && asset.isImage) {
|
||||
// 图片类型分区
|
||||
@ -2668,124 +2678,124 @@ export default {
|
||||
});
|
||||
},
|
||||
prepareAddProgramPreviewAssets() {
|
||||
const canvas = this.$refs.addProgramPreviewCanvas;
|
||||
if (!canvas) return;
|
||||
const canvas = this.$refs.addProgramPreviewCanvas;
|
||||
if (!canvas) return;
|
||||
|
||||
// 动态获取屏幕参数
|
||||
let screenW = this.screenParams.width || 32;
|
||||
let screenH = this.screenParams.height || 64;
|
||||
// 如果角度为90或270,渲染时宽高互换
|
||||
const angle = this.screenParams.angle;
|
||||
const swapWH = angle === 90 || angle === 270;
|
||||
if (swapWH) {
|
||||
[screenW, screenH] = [screenH, screenW];
|
||||
}
|
||||
const renderWidth = 640; // 与实际渲染宽度匹配
|
||||
const scale = Math.min(renderWidth / screenW, 240 / screenH);
|
||||
// 动态获取屏幕参数
|
||||
let screenW = this.screenParams.width || 32;
|
||||
let screenH = this.screenParams.height || 64;
|
||||
// 如果角度为90或270,渲染时宽高互换
|
||||
const angle = this.screenParams.angle;
|
||||
const swapWH = angle === 90 || angle === 270;
|
||||
if (swapWH) {
|
||||
[screenW, screenH] = [screenH, screenW];
|
||||
}
|
||||
const renderWidth = 640; // 与实际渲染宽度匹配
|
||||
const scale = Math.min(renderWidth / screenW, 240 / screenH);
|
||||
|
||||
this.addProgramPreviewAssets = this.addProgramForm.zones.map(zone => {
|
||||
if (zone.playType === 1 && zone.image) {
|
||||
console.log('加载图片', zone.image);
|
||||
// 图片类型,异步加载图片
|
||||
const img = new window.Image();
|
||||
// img.crossOrigin = 'Anonymous';
|
||||
const asset = { img, isImage: true, loaded: false };
|
||||
img.onload = () => {
|
||||
asset.loaded = true;
|
||||
this.drawAddProgramPreview();
|
||||
};
|
||||
img.onerror = (e) => {
|
||||
console.error("Preview image failed to load:", e);
|
||||
};
|
||||
img.src = zone.image;
|
||||
return asset;
|
||||
}
|
||||
if (zone.playType !== 0 || !zone.displayText) {
|
||||
return { pages: [[]], isText: false };
|
||||
}
|
||||
this.addProgramPreviewAssets = this.addProgramForm.zones.map(zone => {
|
||||
if (zone.playType === 1 && zone.image) {
|
||||
// 图片类型,异步加载图片
|
||||
const img = new window.Image();
|
||||
const asset = { img, isImage: true, loaded: false };
|
||||
img.onload = () => {
|
||||
asset.loaded = true;
|
||||
this.drawAddProgramPreview();
|
||||
};
|
||||
img.onerror = (e) => {
|
||||
console.error("Preview image failed to load:", e);
|
||||
};
|
||||
img.src = zone.image;
|
||||
return asset;
|
||||
}
|
||||
if (zone.playType !== 0 || !zone.displayText) {
|
||||
return { pages: [[]], isText: false };
|
||||
}
|
||||
|
||||
// 获取原始字体大小(像素值)
|
||||
const fontSize = parseInt(this.addProgramFontSizes[zone.fontSize] || '16px');
|
||||
// 获取原始字体大小(像素值)
|
||||
const fontSize = parseInt(this.addProgramFontSizes[zone.fontSize] || '16px');
|
||||
|
||||
// 计算缩放后的字体大小
|
||||
const scaledFontSize = Math.max(10, Math.round(fontSize * scale * 0.8)); // 添加0.8缩放系数
|
||||
// 计算缩放后的字体大小
|
||||
const scaledFontSize = Math.max(10, Math.round(fontSize * scale * 0.8)); // 添加0.8缩放系数
|
||||
|
||||
const fontFamily = [
|
||||
'SimSun, 宋体, Songti SC, serif',
|
||||
'SimHei, 黑体, Heiti SC, sans-serif',
|
||||
'KaiTi, 楷体, Kaiti SC, serif'
|
||||
];
|
||||
const fontWeight = zone.fontBold ? 'bold' : 'normal';
|
||||
const fontFamily = [
|
||||
'SimSun, 宋体, Songti SC, serif',
|
||||
'SimHei, 黑体, Heiti SC, sans-serif',
|
||||
'KaiTi, 楷体, Kaiti SC, serif'
|
||||
];
|
||||
const fontWeight = zone.fontBold ? 'bold' : 'normal';
|
||||
|
||||
// 创建临时canvas测量文本
|
||||
const measureCanvas = document.createElement('canvas');
|
||||
const measureCtx = measureCanvas.getContext('2d');
|
||||
const fontFamilies2 = [
|
||||
'SimSun, 宋体, Songti SC, serif',
|
||||
'SimHei, 黑体, Heiti SC, sans-serif',
|
||||
'KaiTi, 楷体, Kaiti SC, serif'
|
||||
];
|
||||
const enFontMap2 = [
|
||||
'Courier New', 'Arial Black', 'Arial Italic', 'Lucida Console', 'Impact', 'Gothic', 'Arial Narrow', 'Comic Sans MS', 'Brush Script MT', 'Century Gothic', 'Times New Roman'
|
||||
];
|
||||
let fontFamily2;
|
||||
if (/^[A-Za-z0-9\s]+$/.test(zone.displayText)) {
|
||||
fontFamily2 = enFontMap2[zone.fontEn] || fontFamilies2[0];
|
||||
// 创建临时canvas测量文本
|
||||
const measureCanvas = document.createElement('canvas');
|
||||
const measureCtx = measureCanvas.getContext('2d');
|
||||
const enFontMap = [
|
||||
'Courier New', 'Arial Black', 'Arial Italic', 'Lucida Console', 'Impact', 'Gothic', 'Arial Narrow', 'Comic Sans MS', 'Brush Script MT', 'Century Gothic', 'Times New Roman'
|
||||
];
|
||||
let fontFamilyUsed;
|
||||
if (/^[A-Za-z0-9\s]+$/.test(zone.displayText)) {
|
||||
fontFamilyUsed = enFontMap[zone.fontEn] || fontFamily[0];
|
||||
} else {
|
||||
fontFamilyUsed = fontFamily[zone.font] || fontFamily[0];
|
||||
}
|
||||
measureCtx.font = `${fontWeight} ${scaledFontSize}px ${fontFamilyUsed}`;
|
||||
|
||||
// 分行逻辑 - 特殊处理连续左移效果
|
||||
let lines = [];
|
||||
if (zone.effect === 5) { // 连续左移效果
|
||||
// 强制不分行,整个文本作为一行
|
||||
lines = [zone.displayText];
|
||||
} else {
|
||||
// 正常的分行逻辑
|
||||
const zoneRenderWidth = swapWH ? zone.height : zone.width;
|
||||
const maxWidth = zoneRenderWidth * scale - 4; // 预留4px边距
|
||||
let currentLine = '';
|
||||
|
||||
for (const char of zone.displayText) {
|
||||
const testLine = currentLine + char;
|
||||
const metrics = measureCtx.measureText(testLine);
|
||||
|
||||
if (metrics.width > maxWidth) {
|
||||
if (currentLine) lines.push(currentLine);
|
||||
currentLine = char;
|
||||
} else {
|
||||
fontFamily2 = fontFamilies2[zone.font] || fontFamilies2[0];
|
||||
currentLine = testLine;
|
||||
}
|
||||
measureCtx.font = `${fontWeight} ${scaledFontSize}px ${fontFamily2}`;
|
||||
}
|
||||
|
||||
// 分行逻辑
|
||||
const zoneRenderWidth = swapWH ? zone.height : zone.width;
|
||||
const maxWidth = zoneRenderWidth * scale - 4; // 预留4px边距
|
||||
let currentLine = '';
|
||||
const lines = [];
|
||||
if (currentLine) lines.push(currentLine);
|
||||
}
|
||||
|
||||
for (const char of zone.displayText) {
|
||||
const testLine = currentLine + char;
|
||||
const metrics = measureCtx.measureText(testLine);
|
||||
// 计算每页最大行数
|
||||
const zoneRenderHeight = swapWH ? zone.width : zone.height;
|
||||
const lineHeight = scaledFontSize * 1.2;
|
||||
const maxLines = Math.max(1, Math.floor((zoneRenderHeight * scale - 4) / lineHeight));
|
||||
|
||||
if (metrics.width > maxWidth) {
|
||||
if (currentLine) lines.push(currentLine);
|
||||
currentLine = char;
|
||||
} else {
|
||||
currentLine = testLine;
|
||||
}
|
||||
}
|
||||
// 分页
|
||||
const pages = [];
|
||||
for (let i = 0; i < lines.length; i += maxLines) {
|
||||
pages.push(lines.slice(i, i + maxLines));
|
||||
}
|
||||
|
||||
if (currentLine) lines.push(currentLine);
|
||||
if (pages.length === 0) pages.push([]);
|
||||
|
||||
// 计算每页最大行数
|
||||
const zoneRenderHeight = swapWH ? zone.width : zone.height;
|
||||
const lineHeight = scaledFontSize * 1.2;
|
||||
const maxLines = Math.max(1, Math.floor((zoneRenderHeight * scale - 4) / lineHeight));
|
||||
// 计算总宽高和区域宽高,供动画用
|
||||
const totalWidth = Math.max(...pages.flat().map(line => measureCtx.measureText(line).width), 0);
|
||||
const totalHeight = Math.min(lines.length, maxLines) * lineHeight;
|
||||
|
||||
// 分页
|
||||
const pages = [];
|
||||
for (let i = 0; i < lines.length; i += maxLines) {
|
||||
pages.push(lines.slice(i, i + maxLines));
|
||||
}
|
||||
|
||||
if (pages.length === 0) pages.push([]);
|
||||
|
||||
// 新增:计算总宽高和区域宽高,供动画用
|
||||
const totalWidth = Math.max(...lines.map(line => measureCtx.measureText(line).width), 0);
|
||||
const totalHeight = lines.length * lineHeight;
|
||||
return {
|
||||
pages,
|
||||
isText: true,
|
||||
scaledFontSize,
|
||||
fontFamily: fontFamily2,
|
||||
fontWeight,
|
||||
lineHeight,
|
||||
totalWidth,
|
||||
totalHeight,
|
||||
zoneRenderWidth: zoneRenderWidth * scale,
|
||||
zoneRenderHeight: zoneRenderHeight * scale
|
||||
};
|
||||
});
|
||||
},
|
||||
return {
|
||||
pages,
|
||||
isText: true,
|
||||
scaledFontSize,
|
||||
fontFamily: fontFamilyUsed,
|
||||
fontWeight,
|
||||
lineHeight,
|
||||
totalWidth,
|
||||
totalHeight,
|
||||
zoneRenderWidth: (swapWH ? zone.height : zone.width) * scale,
|
||||
zoneRenderHeight: (swapWH ? zone.width : zone.height) * scale
|
||||
};
|
||||
});
|
||||
},
|
||||
resetAddProgramPreviewPage() {
|
||||
this.addProgramPreviewPage = this.addProgramForm.zones.map(() => 0);
|
||||
},
|
||||
@ -2881,292 +2891,118 @@ export default {
|
||||
this.addProgramPreviewAnimFrame = requestAnimationFrame(loop);
|
||||
},
|
||||
updateAddProgramPreviewAnimState() {
|
||||
// 动画主循环,更新每个分区的动画状态
|
||||
const renderWidth = 640;
|
||||
const renderHeight = 240;
|
||||
// const scale = Math.min(renderWidth / 32, renderHeight / 64);
|
||||
// 使用与 prepareAddProgramPreviewAssets 中相同的 scale 计算方式
|
||||
let screenW = this.screenParams.width || 32;
|
||||
let screenH = this.screenParams.height || 64;
|
||||
const angle = this.screenParams.angle;
|
||||
const swapWH = angle === 90 || angle === 270;
|
||||
if (swapWH) {
|
||||
[screenW, screenH] = [screenH, screenW];
|
||||
}
|
||||
const scale = Math.min(renderWidth / screenW, renderHeight / screenH);
|
||||
// 动画主循环,更新每个分区的动画状态
|
||||
const renderWidth = 640;
|
||||
const renderHeight = 240;
|
||||
let screenW = this.screenParams.width || 32;
|
||||
let screenH = this.screenParams.height || 64;
|
||||
const angle = this.screenParams.angle;
|
||||
const swapWH = angle === 90 || angle === 270;
|
||||
if (swapWH) {
|
||||
[screenW, screenH] = [screenH, screenW];
|
||||
}
|
||||
const scale = Math.min(renderWidth / screenW, renderHeight / screenH);
|
||||
|
||||
this.addProgramForm.zones.forEach((zone, idx) => {
|
||||
const asset = this.addProgramPreviewAssets[idx];
|
||||
const state = this.addProgramPreviewAnimState[idx];
|
||||
|
||||
this.addProgramForm.zones.forEach((zone, idx) => {
|
||||
const asset = this.addProgramPreviewAssets[idx];
|
||||
const state = this.addProgramPreviewAnimState[idx];
|
||||
if (!asset || !state || !asset.isText) return;
|
||||
|
||||
if (!asset || !state || !asset.isText) return;
|
||||
const effect = zone.effect;
|
||||
const page = this.addProgramPreviewPage[idx] || 0;
|
||||
const pageLines = asset.pages[page] || [];
|
||||
const lineHeight = asset.lineHeight;
|
||||
const totalHeight = asset.totalHeight;
|
||||
const totalWidth = asset.totalWidth;
|
||||
|
||||
const effect = zone.effect;
|
||||
const page = this.addProgramPreviewPage[idx] || 0;
|
||||
const pageLines = asset.pages[page] || [];
|
||||
const lineHeight = asset.lineHeight;
|
||||
// const totalHeight = pageLines.length * lineHeight; // 原始计算
|
||||
// const totalWidth = Math.max(...pageLines.map(line => measureCtx.measureText(line).width), 0); // 原始计算
|
||||
// 使用 prepareAddProgramPreviewAssets 中预先计算好的值
|
||||
const totalHeight = asset.totalHeight;
|
||||
const totalWidth = asset.totalWidth;
|
||||
// 动画速度
|
||||
const speedMap = [1, 2, 3, 4, 5];
|
||||
const animSpeed = (speedMap[zone.speed] || 3) * scale * 0.5; // 像素/帧
|
||||
|
||||
// 区域宽高 (使用预先计算并缩放的值)
|
||||
const zoneWidth = asset.zoneRenderWidth;
|
||||
const zoneHeight = asset.zoneRenderHeight;
|
||||
|
||||
// 动画速度
|
||||
const speedMap = [1, 2, 3, 4, 5];
|
||||
const animSpeed = (speedMap[zone.speed] || 3) * scale * 0.5; // 像素/帧
|
||||
// 暂停时间 (毫秒)
|
||||
const pauseMs = this.getPauseTime(zone.stayTime);
|
||||
|
||||
// 区域宽高 (使用预先计算并缩放的值)
|
||||
const zoneWidth = asset.zoneRenderWidth;
|
||||
const zoneHeight = asset.zoneRenderHeight;
|
||||
// 确保初始状态值存在
|
||||
if (typeof state.isPausing !== 'boolean') state.isPausing = false;
|
||||
if (typeof state.pauseStart !== 'number') state.pauseStart = 0;
|
||||
if (typeof state.pausePhase !== 'string') state.pausePhase = 'start'; // 'start' | 'move'
|
||||
|
||||
// 暂停时间 (毫秒)
|
||||
const pauseMs = this.getPauseTime(zone.stayTime);
|
||||
|
||||
// 确保初始状态值存在
|
||||
if (typeof state.isPausing !== 'boolean') state.isPausing = false;
|
||||
if (typeof state.pauseStart !== 'number') state.pauseStart = 0;
|
||||
if (typeof state.pausePhase !== 'string') state.pausePhase = 'start'; // 'start' | 'move'
|
||||
|
||||
|
||||
switch (effect) {
|
||||
case 1: // 左移
|
||||
// 确保初始 state.currentX 值存在
|
||||
if (typeof state.currentX !== 'number') state.currentX = 0;
|
||||
// 确保初始 pausePhase 值存在
|
||||
if (!state.pausePhase) state.pausePhase = 'start'; // 'start' | 'move'
|
||||
|
||||
// 初始位置停留阶段
|
||||
if (!state.isPausing && state.pausePhase === 'start') {
|
||||
state.isPausing = true;
|
||||
state.pauseStart = Date.now();
|
||||
}
|
||||
|
||||
// 检查初始停留是否结束
|
||||
if (state.isPausing && state.pausePhase === 'start') {
|
||||
if (Date.now() - state.pauseStart >= pauseMs) {
|
||||
state.isPausing = false;
|
||||
state.pausePhase = 'move';
|
||||
}
|
||||
// 移动阶段
|
||||
} else if (!state.isPausing && state.pausePhase === 'move') {
|
||||
// --- 强制多移动的逻辑 ---
|
||||
// !!! 核心修改点 !!!
|
||||
// 原判断: if (state.currentX + totalWidth > 0)
|
||||
// 新判断: 计算从起始位置(0)到当前位置已经移动的距离 (-state.currentX)
|
||||
// 并与一个我们认为足够"移出"的距离进行比较
|
||||
const pixelsMoved = -state.currentX; // 从 X=0 开始,向左移动了多远
|
||||
const distanceToTriggerReset = zoneWidth + 100; // <--- 关键:移出区域宽度 + 额外距离
|
||||
// 例如:区域宽 32 + 额外 100 = 132
|
||||
// 你可以调整这个 100 为你觉得合适的值
|
||||
|
||||
if (pixelsMoved < distanceToTriggerReset) {
|
||||
// 移动距离还不够,继续移动
|
||||
state.currentX -= animSpeed;
|
||||
} else {
|
||||
// 移动距离足够了(强制认为已经移出),立即重置
|
||||
// console.log(`Zone ${idx} - Left Move: Forcefully reset after moving ${pixelsMoved.toFixed(2)} pixels.`); // 调试信息
|
||||
state.currentX = 0; // 回到起始位置
|
||||
state.pausePhase = 'start'; // 回到初始停留阶段
|
||||
}
|
||||
// --- 强制多移动逻辑结束 ---
|
||||
}
|
||||
// Y轴不移动
|
||||
state.currentY = 0;
|
||||
break;
|
||||
|
||||
|
||||
case 2: // 右移
|
||||
// 确保初始 state.currentX 值存在
|
||||
if (typeof state.currentX !== 'number') state.currentX = 0; // 通常从左侧开始向右移
|
||||
// 确保初始 pausePhase 值存在
|
||||
if (!state.pausePhase) state.pausePhase = 'start'; // 'start' | 'move'
|
||||
|
||||
// 初始位置停留阶段
|
||||
if (!state.isPausing && state.pausePhase === 'start') {
|
||||
state.isPausing = true;
|
||||
state.pauseStart = Date.now();
|
||||
}
|
||||
|
||||
// 检查初始停留是否结束
|
||||
if (state.isPausing && state.pausePhase === 'start') {
|
||||
if (Date.now() - state.pauseStart >= pauseMs) {
|
||||
state.isPausing = false;
|
||||
state.pausePhase = 'move';
|
||||
}
|
||||
// 移动阶段
|
||||
} else if (!state.isPausing && state.pausePhase === 'move') {
|
||||
// --- 修正后的逻辑 ---
|
||||
// 判断是否还可以继续向右移动
|
||||
// 条件:当前文本左边缘距离完全移出右边界还有距离 (currentX < zoneWidth)
|
||||
if (state.currentX < zoneWidth) {
|
||||
state.currentX += animSpeed;
|
||||
// 可选:边界检查
|
||||
// if (state.currentX > zoneWidth) {
|
||||
// state.currentX = zoneWidth; // 精确设置到边界
|
||||
// }
|
||||
} else {
|
||||
// 内容完全移出右侧,立即重置,准备下一轮
|
||||
// 不再进入 'end' 停留阶段
|
||||
state.currentX = 0; // 回到左侧起始位置
|
||||
state.pausePhase = 'start'; // 回到初始停留阶段
|
||||
}
|
||||
// --- 修正结束 ---
|
||||
}
|
||||
// Y轴不移动
|
||||
state.currentY = 0;
|
||||
break;
|
||||
|
||||
case 3: // 上移
|
||||
// 确保初始 state.currentY 值存在
|
||||
if (typeof state.currentY !== 'number') state.currentY = 0;
|
||||
// 确保初始 pausePhase 值存在
|
||||
if (!state.pausePhase) state.pausePhase = 'start'; // 'start' | 'move'
|
||||
|
||||
// 初始位置停留阶段
|
||||
if (!state.isPausing && state.pausePhase === 'start') {
|
||||
state.isPausing = true;
|
||||
state.pauseStart = Date.now();
|
||||
}
|
||||
|
||||
// 检查初始停留是否结束
|
||||
if (state.isPausing && state.pausePhase === 'start') {
|
||||
if (Date.now() - state.pauseStart >= pauseMs) {
|
||||
state.isPausing = false;
|
||||
state.pausePhase = 'move';
|
||||
}
|
||||
// 移动阶段
|
||||
} else if (!state.isPausing && state.pausePhase === 'move') {
|
||||
// --- 修正后的逻辑 ---
|
||||
// 判断是否还可以继续向上移动
|
||||
// 条件:当前文本底边距离完全移出顶边还有距离 (currentY + totalHeight > 0)
|
||||
if (state.currentY + totalHeight > 0) {
|
||||
state.currentY -= animSpeed;
|
||||
// 可选:边界检查
|
||||
// if (state.currentY + totalHeight < 0) {
|
||||
// state.currentY = -totalHeight;
|
||||
// }
|
||||
} else {
|
||||
// 内容完全移出顶部,立即重置,准备下一轮
|
||||
// 不再进入 'end' 停留阶段
|
||||
state.currentY = 0; // 回到顶部起始位置
|
||||
state.pausePhase = 'start'; // 回到初始停留阶段
|
||||
}
|
||||
// --- 修正结束 ---
|
||||
}
|
||||
// X轴不移动
|
||||
state.currentX = 0;
|
||||
break;
|
||||
|
||||
case 4: // 下移
|
||||
// 确保初始 state.currentY 值存在
|
||||
if (typeof state.currentY !== 'number') state.currentY = 0; // 通常从顶部开始向下移
|
||||
// 确保初始 pausePhase 值存在
|
||||
if (!state.pausePhase) state.pausePhase = 'start'; // 'start' | 'move'
|
||||
|
||||
// 初始位置停留阶段
|
||||
if (!state.isPausing && state.pausePhase === 'start') {
|
||||
state.isPausing = true;
|
||||
state.pauseStart = Date.now();
|
||||
}
|
||||
|
||||
// 检查初始停留是否结束
|
||||
if (state.isPausing && state.pausePhase === 'start') {
|
||||
if (Date.now() - state.pauseStart >= pauseMs) {
|
||||
state.isPausing = false;
|
||||
state.pausePhase = 'move';
|
||||
}
|
||||
// 移动阶段
|
||||
} else if (!state.isPausing && state.pausePhase === 'move') {
|
||||
// --- 修正后的逻辑 ---
|
||||
// 判断是否还可以继续向下移动
|
||||
// 条件:当前文本顶边距离完全移出底边还有距离 (currentY < zoneHeight)
|
||||
if (state.currentY < zoneHeight) {
|
||||
state.currentY += animSpeed;
|
||||
// 可选:边界检查
|
||||
// if (state.currentY > zoneHeight) {
|
||||
// state.currentY = zoneHeight;
|
||||
// }
|
||||
} else {
|
||||
// 内容完全移出底部,立即重置,准备下一轮
|
||||
// 不再进入 'end' 停留阶段
|
||||
state.currentY = 0; // 回到顶部起始位置
|
||||
state.pausePhase = 'start'; // 回到初始停留阶段
|
||||
}
|
||||
// --- 修正结束 ---
|
||||
}
|
||||
// X轴不移动
|
||||
state.currentX = 0;
|
||||
break;
|
||||
|
||||
case 5: // 连续左移 (立即显示 -> 左移 -> 立即显示 -> ...)
|
||||
// 确保初始 state.currentX 值存在
|
||||
if (typeof state.currentX !== 'number') state.currentX = 0;
|
||||
// 确保初始 pausePhase 值存在
|
||||
if (!state.pausePhase) state.pausePhase = 'start'; // 'start' | 'move'
|
||||
|
||||
// 初始立即显示阶段 (或一轮结束后的显示阶段)
|
||||
if (!state.isPausing && state.pausePhase === 'start') {
|
||||
// 立即显示阶段,不移动,停留 pauseMs 时间
|
||||
state.isPausing = true;
|
||||
state.pauseStart = Date.now();
|
||||
}
|
||||
|
||||
// 检查立即显示阶段是否结束
|
||||
if (state.isPausing && state.pausePhase === 'start') {
|
||||
if (Date.now() - state.pauseStart >= pauseMs) {
|
||||
state.isPausing = false;
|
||||
state.pausePhase = 'move'; // 进入移动阶段
|
||||
}
|
||||
// 移动阶段 (左移)
|
||||
} else if (!state.isPausing && state.pausePhase === 'move') {
|
||||
// --- 修正后的逻辑 (连续左移的移动逻辑与普通左移一致) ---
|
||||
// 判断是否还可以继续向左移动
|
||||
if (state.currentX > -totalWidth) {
|
||||
state.currentX -= animSpeed;
|
||||
// 可选边界检查
|
||||
// if (state.currentX < -totalWidth) {
|
||||
// state.currentX = -totalWidth;
|
||||
// }
|
||||
} else {
|
||||
// 内容完全移出,进入下一个立即显示阶段
|
||||
// 连续左移的效果是在这里停留 pauseMs 后再显示下一轮
|
||||
state.isPausing = true;
|
||||
state.pauseStart = Date.now();
|
||||
state.currentX = 0; // 回到起始位置显示
|
||||
state.pausePhase = 'start'; // 回到 'start' 阶段进行显示停留
|
||||
}
|
||||
// --- 修正结束 ---
|
||||
}
|
||||
state.currentY = 0; // Y轴不移动
|
||||
break;
|
||||
|
||||
case 6: // 闪烁换页
|
||||
// 由自动翻页定时器控制,此处不处理动画位移
|
||||
state.currentX = 0;
|
||||
state.currentY = 0;
|
||||
break;
|
||||
|
||||
default: // 立即显示 (effect === 0) 或其他未知效果
|
||||
state.currentX = 0;
|
||||
state.currentY = 0;
|
||||
// 可以考虑添加立即显示的停留逻辑,如果需要的话
|
||||
// if (!state.isPausing && state.pausePhase === 'start') {
|
||||
// state.isPausing = true;
|
||||
// state.pauseStart = Date.now();
|
||||
// }
|
||||
// if (state.isPausing && state.pausePhase === 'start') {
|
||||
// if (Date.now() - state.pauseStart >= pauseMs) {
|
||||
// state.isPausing = false;
|
||||
// state.pausePhase = 'end'; // 或者重置为 'start'
|
||||
// }
|
||||
// }
|
||||
// state.pausePhase = 'start'; // 重置状态以便下次循环
|
||||
break;
|
||||
switch (effect) {
|
||||
case 1: // 左移
|
||||
if (typeof state.currentX !== 'number') state.currentX = zoneWidth;
|
||||
state.currentX -= animSpeed;
|
||||
if (state.currentX < -totalWidth) {
|
||||
if (asset.pages.length > 1) {
|
||||
state.currentPage = (state.currentPage + 1) % asset.pages.length;
|
||||
}
|
||||
state.currentX = zoneWidth;
|
||||
}
|
||||
});
|
||||
},
|
||||
state.currentY = 0;
|
||||
break;
|
||||
case 2: // 右移
|
||||
if (typeof state.currentX !== 'number') state.currentX = -totalWidth;
|
||||
state.currentX += animSpeed;
|
||||
if (state.currentX > zoneWidth) {
|
||||
if (asset.pages.length > 1) {
|
||||
state.currentPage = (state.currentPage + 1) % asset.pages.length;
|
||||
}
|
||||
state.currentX = -totalWidth;
|
||||
}
|
||||
state.currentY = 0;
|
||||
break;
|
||||
case 3: // 上移
|
||||
if (typeof state.currentY !== 'number') state.currentY = zoneHeight;
|
||||
state.currentY -= animSpeed;
|
||||
if (state.currentY < -totalHeight) {
|
||||
if (asset.pages.length > 1) {
|
||||
state.currentPage = (state.currentPage + 1) % asset.pages.length;
|
||||
}
|
||||
state.currentY = zoneHeight;
|
||||
}
|
||||
state.currentX = 0;
|
||||
break;
|
||||
case 4: // 下移
|
||||
if (typeof state.currentY !== 'number') state.currentY = -totalHeight;
|
||||
state.currentY += animSpeed;
|
||||
if (state.currentY > zoneHeight) {
|
||||
if (asset.pages.length > 1) {
|
||||
state.currentPage = (state.currentPage + 1) % asset.pages.length;
|
||||
}
|
||||
state.currentY = -totalHeight;
|
||||
}
|
||||
state.currentX = 0;
|
||||
break;
|
||||
case 5: // 连续左移 (跑马灯效果)
|
||||
// 确保初始位置在分区右侧外部
|
||||
if (typeof state.currentX !== 'number') state.currentX = zoneWidth;
|
||||
// 向左移动文本
|
||||
state.currentX -= animSpeed;
|
||||
// 当文本完全移出左侧边界时,重置到右侧重新开始(无缝循环)
|
||||
if (state.currentX < -totalWidth) {
|
||||
state.currentX += totalWidth;
|
||||
}
|
||||
// Y轴居中显示
|
||||
state.currentY = (zoneHeight - totalHeight) / 2;
|
||||
break;
|
||||
|
||||
case 6: // 闪烁换页
|
||||
// 由自动翻页定时器控制,此处不处理动画位移
|
||||
state.currentX = 0;
|
||||
state.currentY = 0;
|
||||
break;
|
||||
|
||||
default: // 立即显示 (effect === 0) 或其他未知效果
|
||||
state.currentX = 0;
|
||||
state.currentY = 0;
|
||||
break;
|
||||
}
|
||||
});
|
||||
},
|
||||
measureTextWidth(text, asset) {
|
||||
// 用于动画宽度测量
|
||||
const canvas = document.createElement('canvas');
|
||||
|
Loading…
x
Reference in New Issue
Block a user