Wavesurfer.js多区域拖拽/缩放防重叠问题求助
Wavesurfer.js 字幕区域防重叠拖拽/缩放实现问题修复
问题背景
使用Wavesurfer.js开发视频编辑器,为每条字幕创建可拖拽/缩放的区域,需要实现拖拽或缩放区域时自动防止区域重叠,但现有处理函数未生效。
现有代码
创建区域的代码
let waveSurfer = useRef(null); let wsRegions = useRef(null); const createRegion = () => { if (wsRegions.current) { wsRegions.current.clearRegions(); segments.forEach((segment, index) => { const region = { start: segment.startTime, end: segment.endTime, data: segment, id: index.toString(), content: segment.styledText ? segment.styledText : segment[textType] } wsRegions.current.addRegion(region); }); } }
未生效的重叠处理函数
const handleRegionDrag = async () => { if (!wsRegions.current) { return; } const regions = await wsRegions.current.regions; console.log(regions) if (regions.length === 0) { return; } regions.sort((a, b) => a.start - b.start); for (let i = 0; i < regions.length; i++) { const currentRegion = regions[i]; const previousRegion = regions[i - 1]; const nextRegion = regions[i + 1]; currentRegion.on("click", () => { console.log("Clicked on region with ID:", currentRegion.id); console.log(previousRegion, nextRegion) }); if (nextRegion && currentRegion.end > nextRegion.start) { currentRegion.end = nextRegion.start; } if (previousRegion && currentRegion.start < previousRegion.end) { currentRegion.start = previousRegion.end; } } };
问题分析
- 事件绑定缺失:未将防重叠逻辑绑定到区域的
drag、resize事件上,函数仅会在主动调用时执行,而非拖拽/缩放过程中实时触发。 - 区域更新未触发:直接修改
currentRegion.start或end后,未调用Wavesurfer区域的update()方法,无法同步更新界面显示。 - 逻辑执行时机错误:循环中绑定
click事件会导致重复绑定,且排序后的边界修正逻辑未在每次拖拽/缩放后重新计算。
修复方案
步骤1:在创建区域时绑定事件
修改createRegion函数,为每个区域添加drag和resize事件监听,触发防重叠检查:
const createRegion = () => { if (wsRegions.current) { wsRegions.current.clearRegions(); segments.forEach((segment, index) => { const region = { start: segment.startTime, end: segment.endTime, data: segment, id: index.toString(), content: segment.styledText ? segment.styledText : segment[textType] } const newRegion = wsRegions.current.addRegion(region); // 绑定拖拽和缩放事件 newRegion.on('drag', handleRegionBoundaryCheck); newRegion.on('resize', handleRegionBoundaryCheck); }); } }
步骤2:实现实时防重叠检查函数
重写防重叠逻辑,确保每次拖拽/缩放时实时修正区域边界,并触发界面更新:
const handleRegionBoundaryCheck = () => { if (!wsRegions.current) return; // 获取所有区域并按开始时间排序 const regions = Array.from(wsRegions.current.regions).sort((a, b) => a.start - b.start); regions.forEach((currentRegion, index) => { const prevRegion = regions[index - 1]; const nextRegion = regions[index + 1]; let updated = false; // 处理与前一个区域的重叠 if (prevRegion && currentRegion.start < prevRegion.end) { currentRegion.start = prevRegion.end; updated = true; } // 处理与后一个区域的重叠(确保结束时间不小于开始时间) if (nextRegion && currentRegion.end > nextRegion.start) { currentRegion.end = nextRegion.start; // 防止区域被压缩到0时长 if (currentRegion.end < currentRegion.start) { currentRegion.end = currentRegion.start + 0.1; } updated = true; } // 如果有修改,更新区域 if (updated) { currentRegion.update({ start: currentRegion.start, end: currentRegion.end }); } }); };
额外优化:精准控制拖拽方向
如果需要更精准的控制(比如拖拽区域开始时不覆盖前一个区域,拖拽结束时不覆盖后一个区域),可以在事件回调中获取拖拽的方向参数:
const handleRegionBoundaryCheck = (e, region, update) => { // update参数包含拖拽的是start还是end if (!wsRegions.current) return; const regions = Array.from(wsRegions.current.regions).sort((a, b) => a.start - b.start); const index = regions.findIndex(r => r.id === region.id); const prevRegion = regions[index - 1]; const nextRegion = regions[index + 1]; if (update.start && prevRegion && region.start < prevRegion.end) { region.update({ start: prevRegion.end }); } if (update.end && nextRegion && region.end > nextRegion.start) { region.update({ end: nextRegion.start }); // 保证区域最小时长 if (region.end <= region.start) { region.update({ end: region.start + 0.1 }); } } };
说明
- 每次拖拽或缩放区域时,会实时对所有区域按时间排序,然后逐个检查当前区域与前后区域的边界,修正重叠部分。
- 使用
region.update()方法确保界面同步更新,这是Wavesurfer区域修改后必须调用的方法。 - 添加了最小时长保护,避免区域被压缩到无法识别的状态。
内容的提问来源于stack exchange,提问作者Owais22
相关产品推荐
相关产品推荐

