fix(timeline): 修时间轴无法滚动(flex min-width:auto 坑) + 加鼠标拖拽平移

- 根因:.tl-tracks 作为 flex 子项默认 min-width:auto,被 ~3000px 内容撑大不收缩,
  内部 overflow-x 永不触发→滚轮/滚动条全失效。修复=加 min-width:0
- 新增鼠标按住拖拽平移时间轴(超阈值不算点击,避免误选);滚轮横向滚动;cursor:grab
This commit is contained in:
2026-06-13 20:08:28 +08:00
parent e6ec743564
commit f164ed0a08
2 changed files with 9 additions and 2 deletions

View File

@ -265,7 +265,7 @@ header .who { margin-left:auto; font-size:12px; color:#9a8f7e; }
.tl-choice-btn:hover { background:#5a4a26; border-color:#e6c878; } .tl-choice-btn:hover { background:#5a4a26; border-color:#e6c878; }
/* 时间轴面板:独立、占满剩余高度、自己横向滚动 */ /* 时间轴面板:独立、占满剩余高度、自己横向滚动 */
.tl-timelinepanel { flex:1; min-height:120px; margin-top:8px; display:flex; } .tl-timelinepanel { flex:1; min-height:120px; margin-top:8px; display:flex; }
.tl-tracks { position:relative; flex:1; overflow-x:auto; overflow-y:auto; .tl-tracks { position:relative; flex:1; min-width:0; overflow-x:auto; overflow-y:auto; cursor:grab;
background:#19150f; border:1px solid #3a322a; border-radius:6px; padding-top:20px; } background:#19150f; border:1px solid #3a322a; border-radius:6px; padding-top:20px; }
.tl-ruler { position:relative; height:16px; border-bottom:1px solid #2a2419; } .tl-ruler { position:relative; height:16px; border-bottom:1px solid #2a2419; }
.tl-tick { position:absolute; top:0; height:16px; border-left:1px solid #2a2419; } .tl-tick { position:absolute; top:0; height:16px; border-left:1px solid #2a2419; }

View File

@ -315,6 +315,12 @@
PX = fitMode ? Math.max(6, ((host.clientWidth || 760) - 60) / Math.max(model.total, 0.1)) : PXMAX; PX = fitMode ? Math.max(6, ((host.clientWidth || 760) - 60) / Math.max(model.total, 0.1)) : PXMAX;
// 鼠标滚轮 → 横向滚动(横向溢出时) // 鼠标滚轮 → 横向滚动(横向溢出时)
host.onwheel = e => { if (host.scrollWidth > host.clientWidth + 1) { host.scrollLeft += (e.deltaY || 0) + (e.deltaX || 0); e.preventDefault(); } }; host.onwheel = e => { if (host.scrollWidth > host.clientWidth + 1) { host.scrollLeft += (e.deltaY || 0) + (e.deltaX || 0); e.preventDefault(); } };
// 鼠标按住拖拽 → 平移时间轴(拖动超过阈值则不算点击,避免误选)
let dragging = false, dragX = 0, dragScroll = 0, moved = false;
host.onmousedown = e => { if (e.button !== 0) return; dragging = true; moved = false; dragX = e.clientX; dragScroll = host.scrollLeft; };
host.onmousemove = e => { if (!dragging) return; const dx = e.clientX - dragX; if (Math.abs(dx) > 3) { moved = true; host.style.cursor = "grabbing"; } host.scrollLeft = dragScroll - dx; e.preventDefault(); };
const endDrag = () => { dragging = false; host.style.cursor = ""; };
host.onmouseup = endDrag; host.onmouseleave = endDrag;
const W = model.total * PX; const W = model.total * PX;
const ruler = document.createElement("div"); ruler.className = "tl-ruler"; ruler.style.width = W + "px"; const ruler = document.createElement("div"); ruler.className = "tl-ruler"; ruler.style.width = W + "px";
for (let s = 0; s <= Math.ceil(model.total); s++) { for (let s = 0; s <= Math.ceil(model.total); s++) {
@ -335,7 +341,7 @@
el.textContent = c.label; el.textContent = c.label;
el.dataset.start = c.start; el.dataset.end = c.start + c.dur; el.dataset.start = c.start; el.dataset.end = c.start + c.dur;
if (c.nodeId && S.nodes[c.nodeId]) el.classList.add("startable"); if (c.nodeId && S.nodes[c.nodeId]) el.classList.add("startable");
el.onclick = e => { e.stopPropagation(); selectClip(c, el); }; // 单击=选中(不跳时间,避免视图乱滚) el.onclick = e => { e.stopPropagation(); if (moved) return; selectClip(c, el); }; // 拖动后不算选中
el.ondblclick = e => { e.stopPropagation(); e.preventDefault(); if (c.nodeId && S.nodes[c.nodeId]) startFrom(c.nodeId, true); }; el.ondblclick = e => { e.stopPropagation(); e.preventDefault(); if (c.nodeId && S.nodes[c.nodeId]) startFrom(c.nodeId, true); };
lane.appendChild(el); lane.appendChild(el);
}); });
@ -343,6 +349,7 @@
}); });
const ph = document.createElement("div"); ph.className = "tl-playhead"; host.appendChild(ph); els.playhead = ph; const ph = document.createElement("div"); ph.className = "tl-playhead"; host.appendChild(ph); els.playhead = ph;
host.onclick = e => { host.onclick = e => {
if (moved) return; // 刚才是拖拽,不当作跳转
const rect = host.getBoundingClientRect(); const rect = host.getBoundingClientRect();
seek(Math.max(0, Math.min(model.total, (e.clientX - rect.left + host.scrollLeft) / PX))); seek(Math.max(0, Math.min(model.total, (e.clientX - rect.left + host.scrollLeft) / PX)));
}; };