|
@@ -1224,6 +1224,97 @@ export const followBeatPaly = () => {
|
|
});
|
|
});
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+// 音符添加bbox
|
|
|
|
+export const addNoteBBox = (list: any[]) => {
|
|
|
|
+ let voicesBBox: any = null;
|
|
|
|
+ for (let i = 0; i < list.length; i++) {
|
|
|
|
+ const note = list[i];
|
|
|
|
+ const { svgElement, multipleRestMeasures, totalMultipleRestMeasures, stave } = note;
|
|
|
|
+ /**
|
|
|
|
+ * 兼容合并休止小节没有音符的情况,将合并的小节宽度等分,音符位置就在等分的位置
|
|
|
|
+ */
|
|
|
|
+ let bbox: any = null;
|
|
|
|
+ if (svgElement?.attrs.id) {
|
|
|
|
+ // @ts-ignore
|
|
|
|
+ bbox = document.getElementById(`vf-${svgElement?.attrs?.id}`)?.getBBox();
|
|
|
|
+ bbox = {
|
|
|
|
+ x: bbox.x * state.zoom,
|
|
|
|
+ y: bbox.y * state.zoom,
|
|
|
|
+ width: bbox.width * state.zoom,
|
|
|
|
+ height: bbox.height * state.zoom,
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ // @ts-ignore
|
|
|
|
+ let currentVoicesBBox: any = document.getElementById(`${stave?.attrs?.id}`)?.nextSibling?.getBBox();
|
|
|
|
+ const svgBodyBBox: any = document.getElementById('musicAndSelection')?.getBoundingClientRect();
|
|
|
|
+ if (!currentVoicesBBox && multipleRestMeasures <= totalMultipleRestMeasures) {
|
|
|
|
+ currentVoicesBBox = voicesBBox;
|
|
|
|
+ }
|
|
|
|
+ let nextIndex = i + 1;
|
|
|
|
+ while (!list[nextIndex].id && nextIndex < list.length) {
|
|
|
|
+ nextIndex += 1;
|
|
|
|
+ }
|
|
|
|
+ // 休止小节的开头和下一个音符之间的间距
|
|
|
|
+ let multipleWidth: any = currentVoicesBBox?.width * state.zoom;
|
|
|
|
+ if (list[nextIndex].id) {
|
|
|
|
+ // @ts-ignore
|
|
|
|
+ multipleWidth = document.getElementById(`${list[nextIndex]?.stave?.attrs?.id}`)?.getBBox()?.x * state.zoom - currentVoicesBBox?.x * state.zoom;
|
|
|
|
+ }
|
|
|
|
+ const ratioWidth = multipleWidth / totalMultipleRestMeasures || 0;
|
|
|
|
+ bbox = currentVoicesBBox ? {
|
|
|
|
+ bottom: currentVoicesBBox.bottom,
|
|
|
|
+ height: 30,
|
|
|
|
+ left: currentVoicesBBox.x * state.zoom + ratioWidth * (multipleRestMeasures - 1),
|
|
|
|
+ right: currentVoicesBBox.y,
|
|
|
|
+ top: currentVoicesBBox.top,
|
|
|
|
+ width: 1,
|
|
|
|
+ x: currentVoicesBBox.x * state.zoom + ratioWidth * (multipleRestMeasures - 1),
|
|
|
|
+ y: currentVoicesBBox.y,
|
|
|
|
+ svgBodyLeft: svgBodyBBox?.x,
|
|
|
|
+ } : null;
|
|
|
|
+ voicesBBox = currentVoicesBBox;
|
|
|
|
+ }
|
|
|
|
+ note.bbox = bbox;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 一行谱模式,创建固定的光标
|
|
|
|
+export const createFixedCursor = () => {
|
|
|
|
+ if (!state.isSingleLine) return;
|
|
|
|
+ const svg: any = document.getElementById("osmdSvgPage1");
|
|
|
|
+ state.osmdSvgDom = svg;
|
|
|
|
+ const scrollDom = document.getElementById("musicAndSelection");
|
|
|
|
+ const cursorDom = document.getElementById("cursorImg-0");
|
|
|
|
+ state.fistNoteLeft = cursorDom?.getBoundingClientRect()?.left || 0;
|
|
|
|
+ state.osdmScrollDom = scrollDom;
|
|
|
|
+ state.cursorDom = cursorDom;
|
|
|
|
+ let copyCursor: any = cursorDom?.cloneNode(true);
|
|
|
|
+ if (copyCursor) {
|
|
|
|
+ copyCursor.setAttribute('id','cursor-copy');
|
|
|
|
+ copyCursor.style.position = 'sticky';
|
|
|
|
+ copyCursor.style.zIndex = '2';
|
|
|
|
+ // if (!state.times[0]?.id) {
|
|
|
|
+ // copyCursor.style.left = state.times[0]?.bbox?.x + state.times[0]?.bbox?.width / 3 + 'px';
|
|
|
|
+ // }
|
|
|
|
+ copyCursor.style.left = state.times[0]?.bbox?.x + state.times[0]?.bbox?.width / 2 - 1 + 'px';
|
|
|
|
+ copyCursor.style.height = parseFloat(copyCursor.style.height) * 3 + 'px';
|
|
|
|
+ // copyCursor.style.background = 'red';
|
|
|
|
+ copyCursor && scrollDom?.appendChild(copyCursor);
|
|
|
|
+
|
|
|
|
+ // 创建左侧背景dom
|
|
|
|
+ // @ts-ignore
|
|
|
|
+ const firstMeasureBBox: any = document.querySelector('.vf-measure')?.getBBox();
|
|
|
|
+ const leftDom = document.createElement("div");
|
|
|
|
+ leftDom.style.width = state.times[0]?.bbox?.x - firstMeasureBBox?.x * state.zoom + 'px';
|
|
|
|
+ leftDom.style.height = firstMeasureBBox?.height * state.zoom + 'px';
|
|
|
|
+ leftDom.style.left = firstMeasureBBox?.x * state.zoom + 'px';
|
|
|
|
+ leftDom.style.top = '20px';
|
|
|
|
+ leftDom.classList.add('leftNoteBg');
|
|
|
|
+ scrollDom?.appendChild(leftDom);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
/** 计算首尾音符的间距 */
|
|
/** 计算首尾音符的间距 */
|
|
export const calculateDistance = () => {
|
|
export const calculateDistance = () => {
|
|
const firstNoteRect = document.getElementById(`vf-${state.times[0]?.svgElement?.attrs?.id}`)?.getBoundingClientRect();
|
|
const firstNoteRect = document.getElementById(`vf-${state.times[0]?.svgElement?.attrs?.id}`)?.getBoundingClientRect();
|
|
@@ -1237,15 +1328,16 @@ export const calculateDistance = () => {
|
|
|
|
|
|
/** 跳动svgdom */
|
|
/** 跳动svgdom */
|
|
export const moveSvgDom = () => {
|
|
export const moveSvgDom = () => {
|
|
- const cursorLeft = state.cursorDom?.getBoundingClientRect()?.left || 0;
|
|
|
|
- const leftValue = parseFloat(state.cursorDom.style.left) - 47 - 20;
|
|
|
|
|
|
+ // const cursorLeft = state.cursorDom?.getBoundingClientRect()?.left || 0;
|
|
|
|
+ // const leftValue = parseFloat(state.cursorDom.style.left) - 47 - 20;
|
|
// console.log(cursorLeft,leftValue,'光标位置')
|
|
// console.log(cursorLeft,leftValue,'光标位置')
|
|
// state.osmdSvgDom.style.transform = `translateX(${-leftValue}px)`;
|
|
// state.osmdSvgDom.style.transform = `translateX(${-leftValue}px)`;
|
|
// state.osdmScrollDom.scrollLeft = leftValue
|
|
// state.osdmScrollDom.scrollLeft = leftValue
|
|
|
|
+ // console.log('当前音符',state.activeNoteIndex)
|
|
state.times.forEach((item: any, idx: number) => {
|
|
state.times.forEach((item: any, idx: number) => {
|
|
const svgEl = document.getElementById(`vf-${state.times[idx]?.svgElement?.attrs?.id}`)
|
|
const svgEl = document.getElementById(`vf-${state.times[idx]?.svgElement?.attrs?.id}`)
|
|
const stemEl = document.getElementById(`vf-${state.times[idx]?.svgElement?.attrs?.id}-stem`)
|
|
const stemEl = document.getElementById(`vf-${state.times[idx]?.svgElement?.attrs?.id}-stem`)
|
|
- if (item.i === state.activeNoteIndex && item.svgElement) {
|
|
|
|
|
|
+ if ((item.i === state.activeNoteIndex || item.id === state.times[state.activeNoteIndex].id) && item.svgElement) {
|
|
svgEl?.classList.add('noteActive')
|
|
svgEl?.classList.add('noteActive')
|
|
stemEl?.classList.add('noteActive')
|
|
stemEl?.classList.add('noteActive')
|
|
} else {
|
|
} else {
|
|
@@ -1253,9 +1345,15 @@ export const moveSvgDom = () => {
|
|
stemEl?.classList.remove('noteActive')
|
|
stemEl?.classList.remove('noteActive')
|
|
}
|
|
}
|
|
})
|
|
})
|
|
|
|
+ // document.getElementById('cursor-copy')?.classList.add('cursorAnimate');
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 计算需要移动的距离
|
|
|
|
+ * 当前选中的音符和第一个音符之间的间距
|
|
|
|
+ */
|
|
|
|
+ const distance = state.times[state.activeNoteIndex].bbox?.x - state.times[0].bbox?.x + state.times[state.activeNoteIndex].bbox?.width / 2 - state.times[0].bbox?.width / 2;
|
|
state.osdmScrollDom.scrollTo({
|
|
state.osdmScrollDom.scrollTo({
|
|
- left: leftValue,
|
|
|
|
|
|
+ left: distance,
|
|
behavior: "smooth",
|
|
behavior: "smooth",
|
|
});
|
|
});
|
|
}
|
|
}
|
|
@@ -1263,9 +1361,10 @@ export const moveSvgDom = () => {
|
|
/** 平滑移动svgdom */
|
|
/** 平滑移动svgdom */
|
|
export const smoothMoveSvgDom = () => {
|
|
export const smoothMoveSvgDom = () => {
|
|
const currentTime = getAudioCurrentTime();
|
|
const currentTime = getAudioCurrentTime();
|
|
- const matchNoteIdx = state.times.findIndex((item: any) => {
|
|
|
|
- Math.abs(item.time - currentTime) * 1000 < 100
|
|
|
|
- })
|
|
|
|
|
|
+ const matchNoteIdx = state.times.findIndex((item: any) => Math.abs(item.time - currentTime) * 1000 < 100 )
|
|
|
|
+ // if (matchNoteIdx >= 0) {
|
|
|
|
+ // console.log('匹配',matchNoteIdx,currentTime)
|
|
|
|
+ // }
|
|
|
|
|
|
if (currentTime <= state.fixtime) return;
|
|
if (currentTime <= state.fixtime) return;
|
|
if (currentTime > state.times.last()?.time) return;
|
|
if (currentTime > state.times.last()?.time) return;
|
|
@@ -1277,18 +1376,24 @@ export const smoothMoveSvgDom = () => {
|
|
nextIndex += 1;
|
|
nextIndex += 1;
|
|
nextBBox = state.times[nextIndex]?.bbox;
|
|
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
|
|
|
|
|
|
+ // 下一个音符和当前播放音符之间的间距
|
|
|
|
+ let noteDistance = nextBBox?.x - state.times[state.activeNoteIndex].bbox?.x + nextBBox?.width / 4 - state.times[state.activeNoteIndex].bbox?.width / 4 || 0
|
|
if (noteDistance) {
|
|
if (noteDistance) {
|
|
// 当前的音符和下一个音符之间的时值
|
|
// 当前的音符和下一个音符之间的时值
|
|
const noteDuration = state.times[nextIndex].time - state.times[state.activeNoteIndex]?.time;
|
|
const noteDuration = state.times[nextIndex].time - state.times[state.activeNoteIndex]?.time;
|
|
// 当前时值在该区间的占比
|
|
// 当前时值在该区间的占比
|
|
const playProgress = (currentTime - state.times[state.activeNoteIndex]?.time) / noteDuration;
|
|
const playProgress = (currentTime - state.times[state.activeNoteIndex]?.time) / noteDuration;
|
|
|
|
+ // 如果当前播放的音符是休止小节的,实际没有音符
|
|
|
|
+ // if (!state.times[state.activeNoteIndex]?.id && state.times[state.activeNoteIndex]?.multipleRestMeasures && state.times[state.activeNoteIndex+1].id) {
|
|
|
|
+ // noteDistance = noteDistance - state.times[state.activeNoteIndex]?.bbox?.svgBodyLeft;
|
|
|
|
+ // }
|
|
const distance = noteDistance * playProgress;
|
|
const distance = noteDistance * playProgress;
|
|
|
|
|
|
// 上一个音符和第一个音符的间距
|
|
// 上一个音符和第一个音符的间距
|
|
let preDistance = state.times[state.activeNoteIndex].bbox?.x - state.times[0].bbox?.x + state.times[state.activeNoteIndex].bbox?.width / 4;
|
|
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,'滑动', distance, preDistance, state.osdmScrollDom.scrollLeft, noteDistance, nextIndex, currentTime, noteDuration )
|
|
|
|
+ // console.log('当前音符',state.activeNoteIndex,'距离',noteDistance,'比例',playProgress,'上一个距离',preDistance,'时值',currentTime, noteDuration)
|
|
//console.log('滑动','音符:',state.activeNoteIndex,'小节:', state.activeMeasureIndex)
|
|
//console.log('滑动','音符:',state.activeNoteIndex,'小节:', state.activeMeasureIndex)
|
|
state.osdmScrollDom.scrollLeft = distance + preDistance;
|
|
state.osdmScrollDom.scrollLeft = distance + preDistance;
|
|
} else {
|
|
} else {
|