import { ref } from "vue";
import state, { customData } from "../state"
import { getQuery } from "/src/utils/queryString";
import { setGlobalData } from "/src/utils";
const query: any = getQuery();
interface IItem {
id?: string
y?: number
isLast?: boolean
childIndex?: number[]
}
interface IItemList {
parts: string[],
tieId?: string[],
staveSection?: IItem[],
vfmodifiers?: IItem[],
voltas?: number
vfcurve?: IItem[]
stavenote?: IItem[]
}
interface IMusicList {
[_key: string]: IItemList[]
}
const container = ref();
/** 曲谱配置: 重叠 */
export const resetGivenFormate = () => {
interface IItem {
id?: string
y?: number
isLast?: boolean
childIndex?: number[]
}
interface IItemList {
parts: string[],
tieId?: string[],
staveSection?: IItem[],
vfmodifiers?: IItem[],
voltas?: number
vfcurve?: IItem[]
stavenote?: IItem[]
}
interface IMusicList {
[_key: string]: IItemList[]
}
const musicList: IMusicList = {
'12200': [
{parts: ['0', '1'], tieId: ['1483']},
{parts: ['2'], tieId: ['1463']},
{parts: ['10'], tieId: ['1246']},
{parts: ['11'], tieId: ['2455']},
{parts: ['13'], tieId: ['1488', '1688']},
{parts: ['14', '15'], tieId: ['1272']},
{parts: ['16'], tieId: ['1264', '1368'], staveSection: [{id: 'section-0', y: -10}]},
],
'12420': [
{parts: ['0'], tieId: ['1298', '1405', '1998', '2598', '3229', '2731', '2617']}
],
'7729': [
{parts: ['3'], tieId: ['1498', '1660']}
],
'7439': [
{parts: ['23'], vfmodifiers: [{id: 'modifiers-130', y: -18, isLast: true}]}
],
'12711': [
{ parts: ['0'], voltas: -12},
{ parts: ['4'],voltas: -8},
],
'3581': [
{ parts: ['0'], voltas: -8},
],
'6244': [
{ parts: ['15'], stavenote: [{id: 'vf-auto1608', y: -15}]},
],
'7473': [
{ parts: ['0'], voltas: -8},
]
}
const tieList = musicList[state.cbsExamSongId as string]
if (tieList) {
const partIndex = state.partIndex + ""
const tie = tieList.find((item) => item.parts.includes(partIndex))
if (!tie) return
// 延音线和连线重叠
if (tie.tieId && tie.tieId.length) {
for(let tieIndex = 0; tieIndex < tie.tieId.length; tieIndex++){
const vftie: any = document.querySelector(`#vf-auto${tie.tieId[tieIndex]}-tie`)
const vfcurve = vftie?.parentNode?.parentNode?.querySelectorAll('.vf-curve')
if (vfcurve && vfcurve.length){
for(let i = 0; i < vfcurve.length; i++){
const result = collisionDetection(vftie, vfcurve[i])
if (result.isCollision){
vfcurve[i].style.transform = `translateY(-8px)`;
break;
}
}
}
}
}
// 小节数字
if (tie.staveSection && tie.staveSection.length) {
const sectionList = document.querySelectorAll('.vf-StaveSection')
sectionList.forEach((node, index) => {
node.classList.add(`section-${index}`)
})
for(let i = 0; i < tie.staveSection.length; i++){
const item: any = document.querySelector( '.' + tie.staveSection[i].id)
if (item){
item.style.transform = `translateY(${tie.staveSection[i].y}px)`;
}
}
}
// modifiers 里面的符号
if(tie.vfmodifiers && tie.vfmodifiers.length){
const modifierList = document.querySelectorAll('.vf-modifiers')
modifierList.forEach((node, index) => {
node.classList.add(`modifiers-${index}`)
})
for(let i = 0; i < tie.vfmodifiers.length; i++){
const modifier = tie.vfmodifiers[i]
const item: SVGAElement = document.querySelector( '.' + modifier.id)!
if (item){
if (modifier.isLast){
const lastEle: any = Array.from(item.childNodes).at(-1)
if (lastEle){
lastEle.style.transform = `translateY(${modifier.y}px)`;
}
}
}
}
}
// 房子
if (tie.voltas){
const modifierList = document.querySelectorAll('.vf-Volta') as unknown as HTMLElement[]
modifierList.forEach((node, index) => {
node.style.transform = `translateY(${tie.voltas}px)`;
})
}
// 单个音符
if (tie.stavenote && tie.stavenote.length) {
for(let i = 0; i < tie.stavenote.length; i++){
const item = tie.stavenote[i]
const ele = document.querySelector('#' + item.id)! as unknown as HTMLElement
ele && (ele.style.transform = `translateY(${item.y}px)`)
}
}
}
};
const initNoteCoord = () => {
const allNoteDot: any = Array.from(document.querySelectorAll('.node-dot'));
state.noteCoords = allNoteDot.map((note: any) => {
const note_bbox = note?.getBoundingClientRect?.() || { x: 0, y: 0 };
return {
x: note_bbox.x,
y: note_bbox.y
}
})
console.log(11111,state.noteCoords)
}
export const moveGracePosition = (needTrans?: boolean) => {
/**
* TODO:曲目:摇篮曲(节奏练习)-倚音位置 特殊处理
*/
const specialIds = ['1788850864767643649','1788502467554750466','1789839575249596417','1788501975122489346','1796006876341813249'];
if (specialIds.includes(state.cbsExamSongId) || needTrans) {
const lastCurve: any = Array.from(document.getElementsByClassName('vf-curve'))?.last();
if (lastCurve) {
lastCurve.style.display = 'none';
}
if (state.musicRenderType === 'staff') {
// const transNoteDom = document.getElementById('vf-auto2182')?.getElementsByClassName('vf-modifiers')?.[0];
// const transBeamDom = document.getElementById('auto3167')?.parentNode?.getElementsByClassName('vf-beams')?.[0];
// if (transNoteDom) {
// transNoteDom.style.transform = 'translateX(-0.5rem)';
// }
// if (transBeamDom) {
// transBeamDom.style.transform = 'translateX(-0.5rem)';
// }
} else {
// vf-auto2172 , vf-auto2384
const signatureDom = document.getElementById('auto2670');
const signatureDom2 = document.getElementById('auto2710');
const signatureDom3 = document.getElementById('auto3099');
const signatureDom4 = document.getElementById('auto3339');
const needTransLateDom: any = state.cbsExamSongId == '1789839575249596417' && document.getElementById('vf-auto1554')?.getElementsByClassName('vf-modifier')?.[0];
const arrowDom = state.cbsExamSongId == '1789839575249596417' && document.getElementById('vf-auto1554-lines');
const needTransLateDom2: any = state.cbsExamSongId == '1788501975122489346' && document.getElementById('vf-auto2116')?.getElementsByClassName('vf-modifier')?.[0];
const arrowDom2 = state.cbsExamSongId == '1788501975122489346' && document.getElementById('vf-auto2116-lines');
const needTransLateDom3: any = state.cbsExamSongId == '1788502467554750466' && document.getElementById('vf-auto2122')?.getElementsByClassName('vf-modifier')?.[0];
const arrowDom3 = state.cbsExamSongId == '1788502467554750466' && document.getElementById('vf-auto2122-lines');
if (signatureDom) signatureDom.style.display = 'none';
if (signatureDom2) signatureDom2.style.display = 'none';
if (signatureDom3) signatureDom3.style.display = 'none';
if (signatureDom4) signatureDom4.style.display = 'none';
if (needTransLateDom) needTransLateDom.style.transform = 'translateX(-0.65rem)';
if (needTransLateDom2) needTransLateDom2.style.transform = 'translateX(-0.65rem)';
if (needTransLateDom3) needTransLateDom3.style.transform = 'translateX(-0.65rem)';
if (arrowDom) arrowDom.style.transform = 'translateX(-0.65rem)';
if (arrowDom2) arrowDom2.style.transform = 'translateX(-0.65rem)';
if (arrowDom3) arrowDom3.style.transform = 'translateX(-0.65rem)';
if (arrowDom || arrowDom2 || arrowDom3) {
const path: any = arrowDom ? arrowDom.querySelector('path') : arrowDom2 ? arrowDom2.querySelector('path') : arrowDom3 ? arrowDom3.querySelector('path') : null;
let d = path?.getAttribute("d");
if (d) {
const patchStr = d.split('L')?.last()?.split(" ")?.[0];
let startX = d.split("M")?.[1]?.split(" ")[0] || 0;
startX = startX ? Number(startX) : 0;
let endX = d.split("L")?.last().split(" ")[0] || 0;
endX = endX ? Number(endX) : 0;
const distanceX = endX - startX;
const transX = startX - distanceX;
d = d.replace(`L${patchStr}`,`L${transX}`);
path.setAttribute("d", d);
}
}
}
}
}
// 谱面优化
export const resetFormate = () => {
container.value = document.getElementById('scrollContainer')
// if (state.extStyleConfigJson || !container.value) return;
if (!container.value) return;
moveGracePosition();
// setTimeout(() => {
// initNoteCoord();
// }, 0);
const stafflines: SVGAElement[] = Array.from((container.value as HTMLElement).querySelectorAll(".staffline"));
const baseStep = 4; // 两个元素相间,的间距
const musicalDistance = 28; // 音阶与第一条线谱的间距,默认设置为28
for (let i = 0, len = stafflines.length; i < len; i++) {
const staffline = stafflines[i];
const stafflineBox = staffline.getBBox();
const stafflineCenter = stafflineBox.y + stafflineBox.height / 2;
const vfmeasures: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-measure"));
const vfcurve: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-curve"));
const vfvoices: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-measure > .vf-voices"));
const vfbeams: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-measure > .vf-beams"));
const vfties: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-ties"));
const vflines: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-line"));
const texts: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-measure > .vf-stave text"));
const rects: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-measure > .vf-stave rect[fill=none]"));
const staveSection: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-measure .vf-staveSection"));
const paths: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-measure > .vf-stave path"));
const dotModifiers: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-measure .vf-stopDot"));
const staves: SVGAElement[] = Array.from(staffline.querySelectorAll(".vf-measure > .vf-stave"));
// 获取第一个线谱的y轴坐标
const firstLinePathY = paths[0]?.getBBox().y || 0
// 反复标记 和 小节碰撞
const repetWord = ["To Coda", "D.S. al Coda", "Coda"];
texts
.filter((n) => repetWord.includes(n.textContent || ""))
.forEach((t) => {
vfbeams.forEach((curve) => {
const result = collisionDetection(t, curve);
const prePath: SVGAElement = t?.previousSibling as unknown as SVGAElement;
if (result.isCollision) {
const shift_y = Number(t.getAttribute("y")) - (result.b1 - result.t2) - baseStep + "";
t.setAttribute("y", shift_y);
// console.log('音阶间距',shift_y)
if (prePath && prePath.getAttribute("stroke-width") === "0.3" && prePath.getAttribute("stroke") === "none" && (prePath.getAttribute("d")?.length || 0) > 3000) {
prePath.style.transform = `translateY(${-(result.b1 - result.t2 + baseStep)}px)`;
}
}
});
vfvoices.forEach((curve) => {
const result = collisionDetection(t, curve);
const prePath: SVGAElement = t?.previousSibling as unknown as SVGAElement;
if (result.isCollision) {
const shift_y = Number(t.getAttribute("y")) - (result.b1 - result.t2) - baseStep + "";
t.setAttribute("y", shift_y);
// console.log('音阶间距',shift_y)
if (prePath && prePath.getAttribute("stroke-width") === "0.3" && prePath.getAttribute("stroke") === "none" && (prePath.getAttribute("d")?.length || 0) > 3000) {
prePath.style.transform = `translateY(${-(result.b1 - result.t2 + baseStep)}px)`;
}
}
});
});
// 文字方框和飞线碰撞
staveSection.forEach((t) => {
let shift_y = 0;
[...vfcurve, ...vfties, ...vfvoices].forEach((curve) => {
const result = collisionDetection(t, curve);
if (result.isCollision) {
shift_y = Math.min(shift_y, result.t2 - result.b1 - baseStep);
}
});
t.style.transform = `translateY(${shift_y}px)`;
});
// 文字和小节碰撞
let vftexts = Array.from(staffline.querySelectorAll(".vf-text > text")).filter((n: any) => n.getBBox().y < stafflineCenter);
for (let i = 0; i < vftexts.length; i++) {
const _text = vftexts[i];
for (let j = 0; j < vftexts.length; j++) {
if (_text.textContent === 'second time only') {
// @ts-ignore
_text.style.transform = `translateY(15px)`;
}
if (_text.parentNode === vftexts[j].parentNode) continue;
const result = collisionDetection(_text as SVGAElement, vftexts[j] as SVGAElement);
if (result.isCollision) {
if (_text.textContent === vftexts[j].textContent) {
vftexts[j].parentNode?.removeChild(vftexts[j]);
continue;
}
}
}
}
vftexts = Array.from(staffline.querySelectorAll(".vf-text > text")).filter((n: any) => n.getBBox().y < stafflineCenter);
let maxY = 0;
let _vftexts: SVGAElement[] = [];
vftexts.forEach((vftext: any) => {
const textBox = vftext.getBBox();
if (textBox.y < stafflineCenter) {
maxY = Math.max(maxY, textBox.y + textBox.height);
//console.log('音阶间距',textBox.y, textBox.height)
_vftexts.push(vftext as SVGAElement);
}
});
if (maxY !== 0 && _vftexts.length > 1) {
_vftexts.forEach((vftext) => {
vftext.setAttribute("y", maxY + "");
//console.log('音阶间距',maxY)
});
}
vftexts.forEach((vftext) => {
[...vfcurve, ...vfmeasures, ...vflines].forEach((vfmeasure) => {
let result = collisionDetection(vftext as SVGAElement, vfmeasure);
if (result.isCollision && result.b1 < result.b2 && result.t1 < result.b2 - (result.b2 - result.t2) / 2) {
const shift_y = Number(vftext.getAttribute("y")) - (result.b1 - result.t2) - baseStep + "";
vftext.setAttribute("y", shift_y);
//console.log('音阶间距',shift_y)
}
});
});
vftexts.forEach((vftext) => {
vftexts.forEach((text) => {
if (vftext.parentNode !== text.parentNode && !["marcato", "legato"].includes(vftext.textContent as string)) {
if (["marcato", "legato"].includes(text.textContent as string)) {
const result = collisionDetection(vftext as SVGAElement, text as SVGAElement, 30, 30);
if (result.isCollision) {
const textBBox = (vftext as SVGAElement).getBBox();
text.setAttribute("x", textBBox.x + textBBox.width + 5 + "");
text.setAttribute("y", textBBox.y + textBBox.height - 5 + "");
//console.log('音阶间距',textBBox.y + textBBox.height - 5 + "")
}
} else {
const result = collisionDetection(vftext as SVGAElement, text as SVGAElement);
if (result.isCollision) {
const _y = Number(vftext.getAttribute("y"));
const shift_y = result.b2 - result.t2 < 24 ? 24 : result.b2 - result.t2;
text.setAttribute("y", _y - shift_y - 0.5 + "");
//console.log('音阶间距',_y - shift_y - 0.5 + "")
}
}
}
});
});
// 修改音阶和线谱的间距
const clefList = ['C', 'G', 'D', 'A', 'E', 'B', 'F#', 'C#', 'G#', 'F', 'Bb', 'Eb', 'Ab', 'Db', 'Gb', 'Cb', 'Fb', 'D#', 'A#', 'E#']
const btransList = ['Bb', 'Eb', 'Ab', 'Db', 'Gb', 'Cb', 'Fb']
const jtrsnsList = ['F#', 'C#', 'G#', 'D#', 'A#', 'E#', 'B#']
vftexts.forEach((label: any) => {
const labelText = label.textContent as string
if (clefList.includes(labelText)){
const _y = Number(label.getAttribute("y"))
const endY = firstLinePathY ? firstLinePathY - musicalDistance : _y
label.setAttribute("y", endY)
}
if (btransList.includes(labelText)) {
label.textContent = labelText.replace('b','♭')
}
if (jtrsnsList.includes(labelText)) {
label.textContent = labelText.replace('#','♯')
}
});
dotModifiers.forEach((group: any) => {
if (state.musicRenderType === 'fixedTone') {
group.setAttribute('transform', 'translate(3,-12)')
} else {
group.setAttribute('transform', 'translate(3,-7)')
}
});
const vftextBottom = Array.from(staffline.querySelectorAll(".vf-text > text")).filter((n: any) => n.getBBox().y > stafflineCenter);
const vflineBottom = Array.from(staffline.querySelectorAll(".vf-line")).filter((n: any) => n.getBBox().y > stafflineCenter);
// 去重
for (let i = 0; i < vftextBottom.length; i++) {
const _text = vftextBottom[i];
for (let j = 0; j < vftextBottom.length; j++) {
if (_text.parentNode === vftextBottom[j].parentNode) continue;
const result = collisionDetection(_text as SVGAElement, vftextBottom[j] as SVGAElement);
if (result.isCollision) {
if (_text.textContent === vftextBottom[j].textContent) {
vftextBottom[j].parentNode?.removeChild(vftextBottom[j]);
continue;
}
}
}
}
// 1,2线谱底部文字重叠问题
vftextBottom.forEach((vftext) => {
[...vfmeasures].forEach((n) => {
let result = collisionDetection(vftext as SVGAElement, n);
if (result.isCollision) {
vftext.setAttribute("y", result.b2 + Math.abs(result.t1 - Number(vftext.getAttribute("y"))) + "");
//console.log('音阶间距', result.b2 + Math.abs(result.t1 - Number(vftext.getAttribute("y"))) + "")
}
});
});
// 如果渐弱渐强有平行的文字
vflineBottom.forEach((line) => {
const texts: any[] = [];
if (line.nextElementSibling?.classList.contains("vf-line")) {
vftextBottom.forEach((text) => {
let result = collisionDetection(line as SVGAElement, text as SVGAElement, 20, 20);
if (result.isCollision) {
texts.push({
text: text as SVGAElement,
result,
});
}
});
}
if (texts.length === 1) {
const result = texts[0].result;
const text = texts[0].text;
if (result.x2 + result.w2 < result.x1) {
// 左
if (Math.abs(result.y2 - result.y1) > 10) {
text.setAttribute("y", result.y1 + result.h2 / 2 + "");
//console.log('音阶间距', result.y1 + result.h2 / 2 + "")
}
} else if (result.x2 > result.x1 + result.w1) {
// 右
if (Math.abs(result.y2 - result.y1) > 10) {
text.setAttribute("y", result.y1 + result.h2 / 2 + "");
//console.log('音阶间距', result.y1 + result.h2 / 2 + "")
}
} else {
if (Math.abs(result.x2 - result.x1) < Math.abs(result.x2 + result.w2 - result.x1 - result.w1)) {
// console.log(text, '有交集', '靠左')
text.setAttribute("x", result.x1 - result.w2 - 5 + "");
if (Math.abs(result.y2 - result.y1) > 10) {
text.setAttribute("y", result.y1 + result.h2 / 2 + "");
//console.log('音阶间距', result.y1 + result.h2 / 2 + "")
}
} else {
// console.log(text, '有交集', '靠右')
text.setAttribute("x", result.x1 + result.w1 + 5 + "");
if (Math.abs(result.y2 - result.y1) > 10) {
text.setAttribute("y", result.y1 + result.h2 / 2 + "");
//console.log('音阶间距', result.y1 + result.h2 / 2 + "")
}
}
}
} else if (texts.length === 2) {
const result1 = texts[0].result;
const text1 = texts[0].text;
const result2 = texts[1].result;
const text2 = texts[1].text;
text1.setAttribute("x", result1.x1 - result1.w2 - 5 + "");
if (Math.abs(result1.y2 - result1.y1) > 10) {
text1.setAttribute("y", result1.y1 + result1.h2 / 2 + "");
//console.log('音阶间距', result1.y1 + result1.h2 / 2 + "")
}
text2.setAttribute("x", result2.x1 + result2.w1 + 5 + "");
if (Math.abs(result2.y2 - result2.y1) > 10) {
text2.setAttribute("y", result2.y1 + result2.h2 / 2 + "");
//console.log('音阶间距', result2.y1 + result2.h2 / 2 + "")
}
} else if (texts.length === 3) {
// console.log(texts)
}
});
vftextBottom.forEach((vftext) => {
vftextBottom.forEach((text) => {
if (vftext.parentNode !== text.parentNode && !["marcato", "legato", "cresc.", "Cantabile"].includes(vftext.textContent as string)) {
if (["marcato", "legato", "cresc.", "Cantabile"].includes(text.textContent as string)) {
const result = collisionDetection(vftext as SVGAElement, text as SVGAElement, 30, 30);
if (result.isCollision) {
const textBBox = (vftext as SVGAElement).getBBox();
text.setAttribute("x", textBBox.x + textBBox.width + 5 + "");
text.setAttribute("y", textBBox.y + textBBox.height - 5 + "");
//console.log('音阶间距', textBBox.y + textBBox.height - 5 + "")
}
} else {
const result = collisionDetection(vftext as SVGAElement, text as SVGAElement);
if (result.isCollision) {
text.setAttribute("y", result.y1 + result.h1 + result.h2 + "");
//console.log('音阶间距', result.y1 + result.h1 + result.h2 + "")
}
}
}
});
});
// 同一行内,多个飞线碰撞
for (let index = 0; index < vfcurve.length; index++) {
let nextIndex = index + 1;
const cur = vfcurve[index];
let next = vfcurve[nextIndex];
let checkDone = false;
while (nextIndex <= vfcurve.length - 1 && !checkDone) {
let result = collisionDetection(cur, next);
if (result.isCollision) {
checkDone = true;
next.style.transform = `translateY(-12px)`;
} else {
nextIndex = nextIndex + 1;
next = vfcurve[nextIndex];
}
}
};
// 给小节添加背景色
if (!state.isCreateImg && !state.isPreView) {
staves.forEach((stave: any) => {
const list = [
Array.from(stave?.querySelectorAll(".vf-StaveSection") || []),
Array.from(stave?.querySelectorAll(".vf-Volta") || []),
Array.from(stave?.querySelectorAll(".vf-clef") || []),
Array.from(stave?.querySelectorAll(".vf-keysignature") || []),
Array.from(stave?.querySelectorAll(".vf-Repetition") || []),
Array.from(stave?.getElementsByTagName("text") || []),
].flat();
try {
if (list.length) {
list.forEach((_el: any) => {
stave?.removeChild(_el)
_el?.style?.setProperty("display", "none");
});
}
} catch (error) {}
const bbox = stave?.getBBox() || {};
const bgColor = state.isEvaluatReport ? '#132D4C' : '#609FCF';
const botColor = state.isEvaluatReport ? '#040D1E' : '#2B70A5';
const rect = ``
const rectBottom = ``
// const filterDom = `
//
//
//
// `
const customG = `${rect}${rectBottom}`
try {
if (list.length) {
list.forEach((_el: any) => {
stave?.appendChild(_el)
_el?.style?.removeProperty("display");
});
}
} catch (error) {}
stave.innerHTML = customG + stave.innerHTML;
});
state.vfmeasures = state.vfmeasures.concat(vfmeasures);
}
}
if (!state.isCombineRender && state.isSingleLine) {
transSinglePage();
}
// setTimeout(() => this.resetGlobalText());
};
// 一行谱时,五线谱/简谱的谱面staffLine,居中显示
const transSinglePage = () => {
if (state.isSingleLine && !state.isSimplePage) {
const svgPage = document?.getElementById('osmdSvgPage1')?.getBoundingClientRect();
const staffLine = document?.querySelector('.staffline')?.getBoundingClientRect();
if (svgPage && staffLine && svgPage.height > 200 && state.platform !== 'PC') {
// 需要上移的距离
// console.log('need',svgPage.height,staffLine.height)
const rate = svgPage.height > 400 ? 1.2 : 2;
const needTransTop = (svgPage.height - staffLine.height) / rate;
// @ts-ignore
document.getElementById('osmdSvgPage1').style.transform = `translateY(-${needTransTop}px)`;
// document.querySelector('.staffline').style.transform = `translateY(-${needTransTop}px)`;
// const musicLine = document.querySelector('.staffline').querySelector('.vf-measure').querySelector('.vf-custom-bg').getBoundingClientRect();
// const needTransDistance = svgPage.height / 2 - (musicLine.top - svgPage.top)
// console.log('svg移动距离',needTransDistance)
// // @ts-ignore
// document.getElementById('osmdSvgPage1').style.transform = `translateY(${needTransDistance}px)`
}
}
}
// 技巧文本
const resetGlobalText = () => {
const svg = container.value.querySelector("svg");
if (!svg) return;
const svgBBox = svg.getBBox();
let vfstavetempo: SVGAElement[] = Array.from(container.value.querySelectorAll(".vf-stavetempo")).reduce((eles: SVGAElement[], value: any) => {
if (eles.find((n) => n.outerHTML === value.outerHTML)) value?.parentNode?.removeChild(value);
else eles.push(value);
return eles;
}, []);
const staffline: SVGAElement[] = Array.from(container.value.querySelectorAll(".staffline"));
const vfmeasures: SVGAElement[] = Array.from(container.value.querySelectorAll(".staffline > .vf-measure"));
const vftexts: SVGAElement[] = Array.from(container.value.querySelectorAll(".staffline > .vf-text"));
const vfcurves: SVGAElement[] = Array.from(container.value.querySelectorAll(".staffline > .vf-curve"));
vfstavetempo.forEach((child: SVGAElement) => {
let _y = 0;
[...vfmeasures, ...vftexts, ...vfcurves].forEach((ele) => {
const result = collisionDetection(child as SVGAElement, ele);
if (result.isCollision && (result.b1 < result.b2 || result.r1 > result.l2 || result.l1 < result.r2)) {
_y = Math.min(_y, result.t2 - result.b1);
}
});
if (_y !== 0) {
child.style.transform = `translateY(${_y}px)`;
}
const childBBox = child.getBBox();
const rightY = (childBBox.x + childBBox.width) * 0.7 - Number(svg.getAttribute("width"));
if (rightY > 0) {
[...staffline, ...vfstavetempo].forEach((tempo) => {
if (child != tempo) {
const result = collisionDetection(child as SVGAElement, tempo, Math.abs(rightY), Math.abs(_y));
if (result.isCollision) {
_y = result.t2 - result.b1;
}
}
});
child.style.transform = `translate(-${rightY / 0.7}px,${_y}px)`;
}
});
if (svgBBox.y < 0) {
svg.setAttribute("height", Number(svg.getAttribute("height")) - svgBBox.y + 10);
}
};
// 碰撞检测
const collisionDetection = (a: SVGAElement, b: SVGAElement, distance: number = 0, distance_y: number = 0) => {
const abbox = a.getBBox();
const bbbox = b.getBBox();
let t1 = abbox.y - distance_y;
let l1 = abbox.x - distance;
let r1 = abbox.x + abbox.width + distance;
let b1 = abbox.y + abbox.height + distance_y;
let t2 = bbbox.y;
let l2 = bbbox.x;
let r2 = bbbox.x + bbbox.width;
let b2 = bbbox.y + bbbox.height;
if (b1 < t2 || l1 > r2 || t1 > b2 || r1 < l2) {
// 表示没碰上
return {
isCollision: false,
t1,
l1,
r1,
b1,
t2,
l2,
r2,
b2,
x1: abbox.x,
y1: abbox.y,
x2: bbbox.x,
y2: bbbox.y,
h1: abbox.height,
h2: bbbox.height,
w1: abbox.width,
w2: bbbox.width,
};
} else {
return {
isCollision: true,
t1,
l1,
r1,
b1,
t2,
l2,
r2,
b2,
x1: abbox.x,
y1: abbox.y,
x2: bbbox.x,
y2: bbbox.y,
h1: abbox.height,
h2: bbbox.height,
w1: abbox.width,
w2: bbbox.width,
};
}
};
/** 全局曲谱配置 */
export const setGlobalMusicSheet = () => {
const partIndex = state.partIndex + ""
/** 延音线方向问题 start */
const stavetieList = [
{id: '12644', part_index: '25', direction: 1}
]
const tieItem = stavetieList.find(({id, part_index}) => {
return id == state.cbsExamSongId && part_index == partIndex
})
setGlobalData('tieDirection', tieItem ? tieItem.direction : undefined)
/** 延音线方向问题 end */
const graceList = [
{id: '3509', part_index: '16', direction: 1}
]
const graceItem = graceList.find(({id, part_index}) => {
return id == state.cbsExamSongId && part_index == partIndex
})
if (graceItem){
setGlobalData('graceCustom', {direction: graceItem.direction})
}
const bassDrumList = [
{id: '3030', part_index: '17', line: 4},
{id: '12704', part_index: '23', line: 3}
]
const bassDrumItem = bassDrumList.find(({id, part_index}) => {
return id == state.cbsExamSongId && part_index == partIndex
})
if (bassDrumItem){
setGlobalData('customBassDrum', bassDrumItem.line)
}
/** 打击乐多声部,双声部休止符重叠 end */
/** 符杆朝向 */
const stemDirectionList = [
{
id: '11654',
part_index: '16',
stemNotes: [
{id: 124, direction: 0},
{id: 125, direction: 0},
{id: 126, direction: 0},
{id: 127, direction: 0},
{id: 128, direction: 0}
]
},
{
id: '3581',
part_index: '4',
stemNotes: [
{id: 380, direction: 1},
]
},
{
id: '3470',
part_index: '0',
stemNotes: [
{id: 36, direction: 1},
{id: 37, direction: 1},
]
},
{
id: '3470',
part_index: '11',
stemNotes: [
{id: 33, direction: 1},
{id: 56, direction: 1},
]
},
{
id: '12644',
part_index: '22',
stemNotes: [
{id: 22, direction: 1},
{id: 26, direction: 1},
{id: 135, direction: 1},
{id: 163, direction: 1},
{id: 199, direction: 1},
{id: 204, direction: 1},
{id: 206, direction: 1},
{id: 208, direction: 1},
{id: 210, direction: 1},
{id: 213, direction: 1},
]
},
{
id: '12303',
part_index: '18',
stemNotes: [
{id: 1, direction: 1},
{id: 4, direction: 1},
{id: 6, direction: 1},
{id: 9, direction: 1},
{id: 12, direction: 1},
{id: 14, direction: 1},
]
},
{
id: '12669',
part_index: '24',
stemNotes: [
{id: 65, direction: 1},
{id: 296, direction: 1},
{id: 298, direction: 1},
{id: 300, direction: 1},
{id: 338, direction: 1},
]
},
{
id: '12420',
part_index: '21',
stemNotes: [
{id: 614, direction: 0},
{id: 617, direction: 0},
{id: 619, direction: 0},
{id: 621, direction: 0},
]
},
{
id: '12711',
part_index: '22',
stemNotes: []
},
{
id: '12973',
part_index: '21',
stemNotes: [
{id: 619, direction: 1},
{id: 622, direction: 1},
{id: 745, direction: 1},
]
},
]
const stemDirectionItem = stemDirectionList.find(({id, part_index}) => {
return id == state.cbsExamSongId && part_index == partIndex
})
if (stemDirectionItem) {
setGlobalData('stemDirectionNote', stemDirectionItem.stemNotes)
}
/** vfcure */
const vfcurveList = [
{
id: '12711',
part_index: '4',
vfcurve: [
{MeasureNumberXML: 25, index: 1, bezierEndControlPt: {y: -2}},
{MeasureNumberXML: 33, index: 1, bezierEndControlPt: {y: -2}},
]
},
{
id: '12059',
part_index: '0',
vfcurve: [
{MeasureNumberXML: 15, bezierEndControlPt: {y: 2.8}, bezierEndPt:{y: 1.1}},
{MeasureNumberXML: 16, bezierEndControlPt: {y: -1}},
{MeasureNumberXML: 19, index: 1, bezierEndControlPt: {y: 2}},
{MeasureNumberXML: 20, bezierEndControlPt: {y: -1}},
{MeasureNumberXML: 42, index: 1, bezierEndControlPt: {y: -1.5}, bezierStartControlPt: {y: -1.5}},
{MeasureNumberXML: 46, index: 3, bezierEndControlPt: {y: -1.5}, bezierStartControlPt: {y: -1.5}},
]
},
{
id: '12668',
part_index: '11',
vfcurve: [
{MeasureNumberXML: 8, index: 2, bezierEndControlPt: {y: -3}, bezierStartControlPt:{y: -3}, bezierEndPt:{y: -1}},
]
},
{
id: '11976',
part_index: '0',
vfcurve: [
{MeasureNumberXML: 14, index: 4, bezierEndControlPt: {y: -3}},
{MeasureNumberXML: 14, index: 1, bezierEndPt: {y: 1.5}, bezierEndControlPt: {y: 1}},
]
},
]
const vfcurveItem = vfcurveList.find(({id, part_index}) => {
return id == state.cbsExamSongId && part_index == partIndex
})
if (vfcurveItem) {
setGlobalData('vfcurveItem', vfcurveItem.vfcurve)
}
/** drum set声部 重音 */
const customArtPositionList = [
{id: '12644', part_index: '25'}
]
const customArtPositionItem = customArtPositionList.find(({id, part_index}) => {
return id == state.cbsExamSongId && part_index == partIndex
})
if (customArtPositionItem) {
setGlobalData('customArtPosition', true)
}
/** 全声部声部 - & 全音符 */
const customTenutoList = [
{id: '12645', part_index: '5'}
]
const customTenutoItem = customTenutoList.find(({id, part_index}) => {
return id == state.cbsExamSongId && part_index == partIndex
})
if (customTenutoItem) {
setGlobalData('customTenutoItem', true)
}
/** 全声部声部 > */
const customAccentList = [
{id: '12711', part_index: '22'},
{id: '12711', part_index: '25'},
]
const customAccentItem = customAccentList.find(({id, part_index}) => {
return id == state.cbsExamSongId && part_index == partIndex
})
if (customAccentItem || state.isEvxml) {
setGlobalData('customAccentItem', true)
}
/** 全声部声部 + */
const customLefthandpizzicatoList = [
{id: '12711', part_index: '25'},
{id: '7755', part_index: '10'},
{id: '6226', part_index: '16'},
]
const customLefthandpizzicatoItem = customLefthandpizzicatoList.find(({id, part_index}) => {
return id == state.cbsExamSongId && part_index == partIndex
})
if (customLefthandpizzicatoItem) {
setGlobalData('customLefthandpizzicatoItem', true)
}
}
/** 设置自定义渐慢 */
export const setCustomGradual = () => {
if (state.gradualTimes) {
const detailId = state.cbsExamSongId + "";
const partIndex = state.partIndex + "";
if (["12280"].includes(detailId) && ["24"].includes(partIndex)) {
state.gradualTimes["8"] = "00:26:10";
state.gradualTimes["66"] = "01:53:35";
state.gradualTimes["90"] = "02:41:40";
}
}
};
/** 设置自定义音符数据 */
export const setCustomNoteRealValue = () => {
const detailId = state.cbsExamSongId + "";
const partIndex = state.partIndex + "";
if (["2670"].includes(detailId)) {
customData.customNoteRealValue = {
0: 0.03125,
};
}
if (["12673"].includes(detailId) && ['22'].includes(partIndex)) {
customData.customNoteRealValue = {
208: 0.125,
};
}
if (["12667", "12673"].includes(detailId)){
customData.customNoteCurrentTime = true
}
};