ui交互
This commit is contained in:
1 parent
6f7230458d
commit
ee7b411a01
1 file changed
+35
-12
+35
-12
@@ -25,7 +25,11 @@
|
||||
--border: #ddd;
|
||||
--error: #d13438;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
html, body {
|
||||
margin: 0; padding: 0; height: 100%; overflow: hidden;
|
||||
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 input[type="range"] {
|
||||
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 .tick {
|
||||
@@ -324,7 +333,6 @@
|
||||
let seeking = false; // 用户正在拖动时间轴
|
||||
let duration = 0; // 当前动画时长
|
||||
let isStaticAnimation = false;
|
||||
let wasPlayingBeforeSeek = false; // 记录拖动前是否在播放
|
||||
const FPS = 30;
|
||||
const STATIC_EPSILON = 1e-6;
|
||||
let statusHoldUntil = 0;
|
||||
@@ -634,6 +642,12 @@
|
||||
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) {
|
||||
const value = Math.max(0, Number(seconds) || 0);
|
||||
if (value < 10) return value.toFixed(2) + ' 秒';
|
||||
@@ -1116,29 +1130,38 @@
|
||||
window.location.reload();
|
||||
});
|
||||
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) => {
|
||||
const t = parseFloat(e.target.value);
|
||||
if (state) seekTo(t);
|
||||
if (state) seekTimelineToNearestFrame();
|
||||
});
|
||||
// 时间轴:按下时暂停动画,拖动结束(松开)恢复播放(若之前是播放状态)
|
||||
// 时间轴:开始拖动即暂停,松开后吸附到最近的 30 FPS 整数帧并保持暂停。
|
||||
timeline.addEventListener('pointerdown', () => {
|
||||
seeking = true;
|
||||
wasPlayingBeforeSeek = playing;
|
||||
playing = false;
|
||||
updatePlayButton();
|
||||
});
|
||||
const endTimelineSeek = () => {
|
||||
if (!seeking) return;
|
||||
seekTimelineToNearestFrame();
|
||||
seeking = false;
|
||||
if (wasPlayingBeforeSeek) {
|
||||
playing = true;
|
||||
updatePlayButton();
|
||||
}
|
||||
playing = false;
|
||||
updatePlayButton();
|
||||
timeline.blur();
|
||||
};
|
||||
timeline.addEventListener('pointerup', endTimelineSeek);
|
||||
// 即便指针移出滑块松开,也能恢复
|
||||
// 指针移出滑块后松开时也要完成吸附。
|
||||
window.addEventListener('pointerup', endTimelineSeek);
|
||||
timeline.addEventListener('change', () => {
|
||||
if (seeking || timeline.disabled) return;
|
||||
seekTimelineToNearestFrame();
|
||||
timeline.blur();
|
||||
});
|
||||
|
||||
// ---------- 画布交互:左键拖拽平移,右键回中心,滚轮缩放 ----------
|
||||
canvas.addEventListener('pointerdown', (e) => {
|
||||
|
||||
Reference in new issue
Block a user