|
@@ -451,6 +451,8 @@ const state = reactive({
|
|
|
fistNoteLeft: 0,
|
|
|
/** 是否为单行谱渲染模式 */
|
|
|
isSingleLine: false,
|
|
|
+ /** 首尾音符的间距 */
|
|
|
+ noteDistance: 0,
|
|
|
});
|
|
|
const browserInfo = browser();
|
|
|
let offset_duration = 0;
|
|
@@ -530,7 +532,7 @@ const handlePlaying = () => {
|
|
|
const duration = getAudioDuration();
|
|
|
state.playProgress = (currentTime / duration) * 100;
|
|
|
let item = getNote(currentTime);
|
|
|
- // console.log(11111,currentTime,duration,state.playSource, item.i)
|
|
|
+ // console.log(11111,currentTime,duration,state.playSource, item)
|
|
|
// console.log(item.i,item.noteId,item.measureSpeed)
|
|
|
// 练习模式下,实时刷新小节速度
|
|
|
if (item && state.modeType === "practise" && state.playState === "play" && item.measureSpeed && item.measureSpeed !== state.playIngSpeed) {
|
|
@@ -597,6 +599,11 @@ const handlePlaying = () => {
|
|
|
// metronomeData.metro?.sound(currentTime);
|
|
|
// }
|
|
|
metronomeData.metro?.sound(currentTime);
|
|
|
+ // 一行谱,需要滚动小节
|
|
|
+ if (state.isSingleLine) {
|
|
|
+ smoothMoveSvgDom();
|
|
|
+ }
|
|
|
+
|
|
|
};
|
|
|
/** 跳转到指定音符开始播放 */
|
|
|
export const skipNotePlay = async (itemIndex: number, isStart = false) => {
|
|
@@ -776,7 +783,7 @@ export const gotoNext = (note: any) => {
|
|
|
}
|
|
|
// 一行谱,需要滚动小节
|
|
|
if (state.isSingleLine) {
|
|
|
- moveSvgDom(50);
|
|
|
+ moveSvgDom();
|
|
|
}
|
|
|
scrollViewNote();
|
|
|
};
|
|
@@ -1217,18 +1224,76 @@ export const followBeatPaly = () => {
|
|
|
});
|
|
|
};
|
|
|
|
|
|
-let moveX = 0;
|
|
|
-/** 移动svgdom */
|
|
|
-export const moveSvgDom = (offset: number) => {
|
|
|
- moveX += offset;
|
|
|
- // state.osmdSvgDom.style.transform = `translateX(${moveX}px)`;
|
|
|
+/** 计算首尾音符的间距 */
|
|
|
+export const calculateDistance = () => {
|
|
|
+ const firstNoteRect = document.getElementById(`vf-${state.times[0]?.svgElement?.attrs?.id}`)?.getBoundingClientRect();
|
|
|
+ const lastNoteRect = document.getElementById(`vf-${state.times.last()?.svgElement?.attrs?.id}`)?.getBoundingClientRect();
|
|
|
+ if (firstNoteRect && lastNoteRect) {
|
|
|
+ const noteDistance = lastNoteRect.x - firstNoteRect.x + lastNoteRect.width / 3;
|
|
|
+ console.log('首尾间距', noteDistance)
|
|
|
+ state.noteDistance = noteDistance || 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/** 跳动svgdom */
|
|
|
+export const moveSvgDom = () => {
|
|
|
const cursorLeft = state.cursorDom?.getBoundingClientRect()?.left || 0;
|
|
|
- const leftValue = parseFloat(state.cursorDom.style.left) - 47 - 20
|
|
|
+ const leftValue = parseFloat(state.cursorDom.style.left) - 47 - 20;
|
|
|
// console.log(cursorLeft,leftValue,'光标位置')
|
|
|
// state.osmdSvgDom.style.transform = `translateX(${-leftValue}px)`;
|
|
|
// state.osdmScrollDom.scrollLeft = leftValue
|
|
|
+ state.times.forEach((item: any, idx: number) => {
|
|
|
+ const svgEl = document.getElementById(`vf-${state.times[idx]?.svgElement?.attrs?.id}`)
|
|
|
+ const stemEl = document.getElementById(`vf-${state.times[idx]?.svgElement?.attrs?.id}-stem`)
|
|
|
+ if (item.i === state.activeNoteIndex && item.svgElement) {
|
|
|
+ svgEl?.classList.add('noteActive')
|
|
|
+ stemEl?.classList.add('noteActive')
|
|
|
+ } else {
|
|
|
+ svgEl?.classList.remove('noteActive')
|
|
|
+ stemEl?.classList.remove('noteActive')
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
state.osdmScrollDom.scrollTo({
|
|
|
left: leftValue,
|
|
|
behavior: "smooth",
|
|
|
});
|
|
|
+}
|
|
|
+
|
|
|
+/** 平滑移动svgdom */
|
|
|
+export const smoothMoveSvgDom = () => {
|
|
|
+ const currentTime = getAudioCurrentTime();
|
|
|
+ const matchNoteIdx = state.times.findIndex((item: any) => {
|
|
|
+ Math.abs(item.time - currentTime) * 1000 < 100
|
|
|
+ })
|
|
|
+
|
|
|
+ if (currentTime <= state.fixtime) return;
|
|
|
+ if (currentTime > state.times.last()?.time) return;
|
|
|
+ // console.log('跳转音符',currentTime)
|
|
|
+ const currentBBox = state.times[state.activeNoteIndex]?.bbox;
|
|
|
+ let nextIndex = state.activeNoteIndex + 1;
|
|
|
+ let nextBBox = state.times[nextIndex]?.bbox;
|
|
|
+ while (!nextBBox && nextIndex < state.times.length) {
|
|
|
+ nextIndex += 1;
|
|
|
+ nextBBox = state.times[nextIndex]?.bbox;
|
|
|
+ }
|
|
|
+ // 下一个音符和第一个音符之间的间距
|
|
|
+ const noteDistance = nextBBox?.x - state.times[state.activeNoteIndex].bbox?.x + nextBBox?.width / 4 - state.times[state.activeNoteIndex].bbox?.width / 4 || 0
|
|
|
+ if (noteDistance) {
|
|
|
+ // 当前的音符和下一个音符之间的时值
|
|
|
+ const noteDuration = state.times[nextIndex].time - state.times[state.activeNoteIndex]?.time;
|
|
|
+ // 当前时值在该区间的占比
|
|
|
+ const playProgress = (currentTime - state.times[state.activeNoteIndex]?.time) / noteDuration;
|
|
|
+ const distance = noteDistance * playProgress;
|
|
|
+
|
|
|
+ // 上一个音符和第一个音符的间距
|
|
|
+ let preDistance = state.times[state.activeNoteIndex].bbox?.x - state.times[0].bbox?.x + state.times[state.activeNoteIndex].bbox?.width / 4;
|
|
|
+ // console.log('滑动', distance, preDistance, state.osdmScrollDom.scrollLeft, noteDistance, state.activeNoteIndex, nextIndex, currentTime )
|
|
|
+ //console.log('滑动','音符:',state.activeNoteIndex,'小节:', state.activeMeasureIndex)
|
|
|
+ state.osdmScrollDom.scrollLeft = distance + preDistance;
|
|
|
+ } else {
|
|
|
+ const playProgress = (currentTime - state.times[0]?.time) / state.times.last()?.time
|
|
|
+ const distance = state.noteDistance * playProgress;
|
|
|
+ state.osdmScrollDom.scrollLeft = distance;
|
|
|
+ }
|
|
|
}
|