import { computed, defineComponent, onMounted, reactive, Transition, nextTick, watch } from "vue"; import state, { EnumMusicRenderType, handleSelection, skipNotePlay, IPlatform, resetBaseRate } from "/src/state"; import styles from "./index.module.less"; import { metronomeData } from "/src/helpers/metronome"; import { evaluatingData } from "../evaluating"; import { leveByScoreMeasureIcons } from "../evaluating/evaluatResult"; import { Icon, showToast } from "vant"; import MoveMusicScore, { moveData, renderForMoveData } from "../plugins/move-music-score"; import { useRoute } from "vue-router"; import { getQuery } from "/src/utils/queryString"; import IntonationDown from "./imgs/pitchLow.png" import IntonationUp from "./imgs/pitchHigh.png" import MultipleRestMeasures from "./multipleRestMeasures" import { browser } from "../../utils"; import { transform } from "lodash"; export default defineComponent({ name: "selection", setup() { const browsInfo = browser(); const isPad = navigator?.userAgent?.includes("UAWEIVRD-W09") || browsInfo?.iPad || browsInfo.isTablet; const route = useRoute(); const query: any = { ...getQuery(), ...route.query, }; const selectData = reactive({ notes: [] as any[], staves: [] as any[], measureHeight: 0 as number, // 小节高度 }); /** 计算点击层数据 */ const calcNoteData = () => { const musicContainer = document.getElementById("musicAndSelection")?.getBoundingClientRect() || { x: 0, y: 0, }; const parentLeft = musicContainer.x || 0; const parentTop = musicContainer.y || 0; const notes = state.times; const notesList: string[] = []; const MeasureNumberXMLList: number[] = []; let minMeasureHeigt: number = 0; for (let i = 0; i < notes.length; i++) { const item = notes[i]; // console.log("🚀 ~ item:", item) const noteItem = { ...item, index: item.i, bbox: null as any, staveBox: null as any, }; if (!notesList.includes(item.noteId)) { let staveBbox: any = {}, customBgBox: any = {}; if (item.stave?.attrs?.id) { const staveEle = document.querySelector(`#${item.stave.attrs.id}`); staveBbox = staveEle?.parentElement?.parentElement?.getBoundingClientRect?.() || { x: 0, width: 0, }; customBgBox = staveEle?.querySelector('.vf-custom-bg')?.getBoundingClientRect() || { y: 0, height: 0 } // console.log("🚀 ~ staveBbox:", staveBbox.height) } if (item.svgElement) { const noteEle = document.querySelector(`#vf-${item.svgElement?.attrs?.id}`); if (noteEle) { const noteBbox = noteEle.getBoundingClientRect?.() || { x: 0, width: 0 }; if (state.musicRenderType !== EnumMusicRenderType.staff) { noteItem.bbox = { left: noteBbox.x - parentLeft - noteBbox.width / 4 + "px", top: noteBbox.y - parentTop - noteBbox.height + "px", width: noteBbox.width * 1.5 + "px", height: noteBbox.height * 3 + "px", x: item.bbox?.x, y: item.bbox?.y, originWidth: item.bbox?.width }; const noteHead = noteEle.querySelector(".vf-numbered-note-head"); const noteHeadBbox = noteHead?.getBoundingClientRect?.(); if (noteHeadBbox) { item.bbox = { left: noteHeadBbox.x - parentLeft - noteHeadBbox.width / 4, width: noteHeadBbox.width * 1.5, x: item.bbox?.x, y: item.bbox?.y, originWidth: item.bbox?.width } } } else { const needTransY = -(staveBbox.height - customBgBox.height) / 2 + "px"; noteItem.bbox = { left: noteBbox.x - parentLeft - noteBbox.width / 4 + "px", top: customBgBox.y ? customBgBox.y - parentTop + "px" : staveBbox.y - parentTop + "px", width: noteBbox.width * 1.5 + "px", height: staveBbox.height + "px", x: item.bbox?.x, y: item.bbox?.y, originWidth: item.bbox?.width, transform: `translateY(${needTransY})` }; } } if (selectData.notes.find((item:any) => item.id === noteItem.id)) { // } else { selectData.notes.push(noteItem); } // selectData.notes.push(noteItem); notesList.push(item.noteId); } } if (!MeasureNumberXMLList.includes(item.MeasureNumberXML)) { if (item.stave) { if (item.stave?.attrs?.id) { const staveEle = document.querySelector(`#${item.stave.attrs.id}`); const list = [ Array.from(staveEle?.querySelectorAll(".vf-clef") || []), Array.from(staveEle?.querySelectorAll(".vf-keysignature") || []), Array.from(staveEle?.getElementsByTagName("text") || []), ].flat(); try { if (list.length) { // console.log("🚀 ~ list:", list) list.forEach((_el: any) => { _el?.style?.setProperty("display", "none"); }); } } catch (error) {} const staveBbox = staveEle?.getBoundingClientRect?.() || { x: 0, width: 0, y: 0, height: 0 }; if (i === 0) { minMeasureHeigt = staveBbox.height } try { if (list.length) { list.forEach((_el: any) => { _el?.style?.removeProperty("display"); }); } } catch (error) {} // console.log("🚀 ~ staveEle:", staveBbox.height) selectData.measureHeight = staveBbox.height let compareVal = staveBbox.height - minMeasureHeigt compareVal = compareVal > 0 ? compareVal : 0 noteItem.staveBox = { left: staveBbox.x - parentLeft + "px", // top: ((item.stave.y || 0) - 5) * state.zoom + "px", top: staveBbox.y - parentTop + compareVal + "px", width: staveBbox.width + "px", height: staveBbox.height - compareVal + "px", // background: 'rgba(0,0,0,.2)' }; selectData.staves.push(noteItem); } MeasureNumberXMLList.push(item.MeasureNumberXML); } else { if (item.multipleRestMeasures) { if (state.isCombineRender) { let currentItem = null; for (let index = 0; index < state.vfmeasures.length; index++) { const element = state.vfmeasures[index]; const measureNum = element.getAttribute('data-num') ? Number(element.getAttribute('data-num')) : -1; const nextMeasureNum = state.vfmeasures[index+1]?.getAttribute('data-num') ? Number(state.vfmeasures[index+1]?.getAttribute('data-num')) : -1; if (measureNum === item.MeasureNumberXML || item.MeasureNumberXML < nextMeasureNum || nextMeasureNum == -1) { currentItem = element break; } } const staveBbox = currentItem?.querySelector('.vf-stave')?.getBoundingClientRect() || { x: 0, width: 0, y: 0, height: 0 }; if (currentItem) { noteItem.staveBox = { left: staveBbox.x - parentLeft + "px", // top: ((item.stave.y || 0) - 5) * state.zoom + "px", top: staveBbox.y - parentTop + "px", width: staveBbox.width + "px", height: staveBbox.height + "px", // height: preItem.staveBox.height, }; selectData.staves.push(noteItem); MeasureNumberXMLList.push(item.MeasureNumberXML); } } else { const preItem = selectData.staves.find( (n: any) => n.MeasureNumberXML === item.MeasureNumberXML - 1 ); if (preItem?.staveBox) { noteItem.staveBox = { left: preItem.staveBox.left, top: preItem.staveBox.top, width: preItem.staveBox.width, // height: preItem.staveBox.height, }; selectData.staves.push(noteItem); MeasureNumberXMLList.push(item.MeasureNumberXML); } } } } } } // 部分浏览器渲染的第一小节的位置信息会包含拍号、调号,需要处理一下,剔除掉拍号、调号的位置 if (selectData.staves[0]?.staveBox?.top !== selectData.staves[1]?.staveBox?.top) { selectData.staves[0].staveBox.top = selectData.staves[1]?.staveBox?.top || selectData.staves[0]?.staveBox?.top } console.log("🚀 ~ selectData.notes:", selectData.notes, selectData.staves); }; /** 是否可以点击音符 */ const disableClickNote = computed(() => { return (state.sectionStatus && state.section.length != 2) || (state.modeType === "evaluating"); }); // 选段符号 const sectionPosData = computed(() => { if(state.sectionStatus) { return state.section.map(((item,index) => { if(index === 0){ const currItem = selectData.staves.find(stave => { return stave.MeasureNumberXML === item.MeasureNumberXML }) // 获取stave里面vf-custom-bg的位置坐标,才是准确的坐标 const currBgX = document.getElementById(currItem.stave.attrs.id)?.querySelector('.vf-custom-bg')?.getBoundingClientRect()?.x || 0; return currItem && { left: currBgX ? currBgX + 'px' : currItem.staveBox.left, top: currItem.staveBox.top, height: selectData.measureHeight + 'px' // 小节的高度 } } else { // 实际的结束位置 const actualEndIndex = state.userChooseEndIndex > item.MeasureNumberXML ? state.userChooseEndIndex : item.MeasureNumberXML const currItem = selectData.staves.find(stave => { return stave.MeasureNumberXML === actualEndIndex }) return currItem && { left: parseFloat(currItem.staveBox.left)+parseFloat(currItem.staveBox.width)-2 +"px", top: currItem.staveBox.top, height: selectData.measureHeight + 'px' } } })) } return [] }) onMounted(() => { selectData.notes = []; selectData.staves = []; calcNoteData(); const img: HTMLElement = document.querySelector('#cursorImg-0')! if (metronomeData.cursorMode === 2){ img.classList.add('lineHide') } else { img.classList.remove('lineHide') } // 初始化谱面可移动的元素位置 try { moveData.partIndex = state.partIndex + "" // 速度标记元素和谱面并非同时渲染,初始化可移动元素的时候,需要加个延迟 setTimeout(() => { renderForMoveData() }, 0); } catch (error) {} }); return () => ( <>