This commit is contained in:
tianmo committed 2026-09-11 12:53:36 +08:00
1 parent 6f7230458d
commit ee7b411a01
1 file changed
+35 -12
+35 -12
View File
@@ -25,7 +25,11 @@
--border: #ddd; --border: #ddd;
--error: #d13438; --error: #d13438;
} }
* { box-sizing: border-box; } * {
box-sizing: border-box;
-webkit-user-select: none;
user-select: none;
}
html, body { html, body {
margin: 0; padding: 0; height: 100%; overflow: hidden; margin: 0; padding: 0; height: 100%; overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
@@ -135,6 +139,11 @@
#timelineBar .tl-wrap { position: relative; flex: 1; padding-top: 20px; } #timelineBar .tl-wrap { position: relative; flex: 1; padding-top: 20px; }
#timelineBar input[type="range"] { #timelineBar input[type="range"] {
display: block; width: 100%; margin: 0; accent-color: var(--accent); display: block; width: 100%; margin: 0; accent-color: var(--accent);
outline: none; box-shadow: none; -webkit-tap-highlight-color: transparent;
}
#timelineBar input[type="range"]:focus,
#timelineBar input[type="range"]:focus-visible {
outline: none; box-shadow: none; border-color: var(--border);
} }
#timeRuler { position: absolute; top: 0; left: 7px; right: 7px; height: 19px; } #timeRuler { position: absolute; top: 0; left: 7px; right: 7px; height: 19px; }
#timeRuler .tick { #timeRuler .tick {
@@ -324,7 +333,6 @@
let seeking = false; // 用户正在拖动时间轴 let seeking = false; // 用户正在拖动时间轴
let duration = 0; // 当前动画时长 let duration = 0; // 当前动画时长
let isStaticAnimation = false; let isStaticAnimation = false;
let wasPlayingBeforeSeek = false; // 记录拖动前是否在播放
const FPS = 30; const FPS = 30;
const STATIC_EPSILON = 1e-6; const STATIC_EPSILON = 1e-6;
let statusHoldUntil = 0; let statusHoldUntil = 0;
@@ -634,6 +642,12 @@
return Math.round((seconds || 0) * FPS); return Math.round((seconds || 0) * FPS);
} }
function snapTimeToFrame(seconds) {
const lastWholeFrame = Math.max(0, Math.floor((duration + 1e-8) * FPS));
const frame = Math.max(0, Math.min(Math.round((Number(seconds) || 0) * FPS), lastWholeFrame));
return frame / FPS;
}
function formatSeconds(seconds) { function formatSeconds(seconds) {
const value = Math.max(0, Number(seconds) || 0); const value = Math.max(0, Number(seconds) || 0);
if (value < 10) return value.toFixed(2) + ' 秒'; if (value < 10) return value.toFixed(2) + ' 秒';
@@ -1116,29 +1130,38 @@
window.location.reload(); window.location.reload();
}); });
document.getElementById('thumbBtn').addEventListener('click', generateThumbnail); document.getElementById('thumbBtn').addEventListener('click', generateThumbnail);
// 时间轴:拖动时实时跳帧 function seekTimelineToNearestFrame() {
const snappedTime = snapTimeToFrame(parseFloat(timeline.value));
timeline.value = String(snappedTime);
seekTo(snappedTime);
}
// 时间轴:拖动时按 30 FPS 整数帧实时预览。
timeline.addEventListener('input', (e) => { timeline.addEventListener('input', (e) => {
const t = parseFloat(e.target.value); if (state) seekTimelineToNearestFrame();
if (state) seekTo(t);
}); });
// 时间轴:按下时暂停动画,拖动结束(松开)恢复播放(若之前是播放状态) // 时间轴:开始拖动即暂停,松开后吸附到最近的 30 FPS 整数帧并保持暂停。
timeline.addEventListener('pointerdown', () => { timeline.addEventListener('pointerdown', () => {
seeking = true; seeking = true;
wasPlayingBeforeSeek = playing;
playing = false; playing = false;
updatePlayButton(); updatePlayButton();
}); });
const endTimelineSeek = () => { const endTimelineSeek = () => {
if (!seeking) return; if (!seeking) return;
seekTimelineToNearestFrame();
seeking = false; seeking = false;
if (wasPlayingBeforeSeek) { playing = false;
playing = true; updatePlayButton();
updatePlayButton(); timeline.blur();
}
}; };
timeline.addEventListener('pointerup', endTimelineSeek); timeline.addEventListener('pointerup', endTimelineSeek);
// 即便指针移出滑块松开,也能恢复 // 指针移出滑块后松开时也要完成吸附。
window.addEventListener('pointerup', endTimelineSeek); window.addEventListener('pointerup', endTimelineSeek);
timeline.addEventListener('change', () => {
if (seeking || timeline.disabled) return;
seekTimelineToNearestFrame();
timeline.blur();
});
// ---------- 画布交互:左键拖拽平移,右键回中心,滚轮缩放 ---------- // ---------- 画布交互:左键拖拽平移,右键回中心,滚轮缩放 ----------
canvas.addEventListener('pointerdown', (e) => { canvas.addEventListener('pointerdown', (e) => {