|
@@ -155,22 +155,23 @@ export default defineComponent({
|
|
|
|
|
|
onMounted(async () => {
|
|
|
if (rendered.value) return
|
|
|
- if (!musicInfo.musicSvg || props.isSoundEffect) {
|
|
|
- setOsdm()
|
|
|
- return
|
|
|
- }
|
|
|
- if (SettingState.sett.type === 'staff') {
|
|
|
- renderData.value = musicInfo.musicSvg?.staff
|
|
|
- } else {
|
|
|
- //是否固定调
|
|
|
- renderData.value = SettingState.sett.keySignature ? musicInfo.musicSvg?.fixedTone : musicInfo.musicSvg?.firstTone
|
|
|
- }
|
|
|
- // console.log("🚀 ~ renderData:", renderData)
|
|
|
- if (renderData.value && renderData.value.json) {
|
|
|
- productJsonAndSvg(renderData.value)
|
|
|
- } else {
|
|
|
- setOsdm()
|
|
|
- }
|
|
|
+ setOsdm()
|
|
|
+ // 暂时不使用缓存
|
|
|
+ // if (!musicInfo.musicSvg || props.isSoundEffect) {
|
|
|
+ // return
|
|
|
+ // }
|
|
|
+ // if (SettingState.sett.type === 'staff') {
|
|
|
+ // renderData.value = musicInfo.musicSvg?.staff
|
|
|
+ // } else {
|
|
|
+ // //是否固定调
|
|
|
+ // renderData.value = SettingState.sett.keySignature ? musicInfo.musicSvg?.fixedTone : musicInfo.musicSvg?.firstTone
|
|
|
+ // }
|
|
|
+ // // console.log("🚀 ~ renderData:", renderData)
|
|
|
+ // if (renderData.value && renderData.value.json) {
|
|
|
+ // productJsonAndSvg(renderData.value)
|
|
|
+ // } else {
|
|
|
+ // setOsdm()
|
|
|
+ // }
|
|
|
})
|
|
|
|
|
|
onUnmounted(() => {
|
|
@@ -214,7 +215,6 @@ export default defineComponent({
|
|
|
await useOsmdLoader(osmd.value, renderScore)
|
|
|
emit('rerender', osmd.value)
|
|
|
event.emit('loaded')
|
|
|
- // resetFormate()
|
|
|
} catch (error) {
|
|
|
console.error(error)
|
|
|
emit('renderError')
|
|
@@ -234,367 +234,6 @@ export default defineComponent({
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- const resetFormate = () => {
|
|
|
- const stafflines: SVGAElement[] = Array.from((container.value as HTMLElement).querySelectorAll('.staffline'))
|
|
|
- const baseStep = 4 // 两个元素相间,的间距
|
|
|
- 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 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)
|
|
|
- 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)
|
|
|
- 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)`
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
- })
|
|
|
- // 文字方框和飞线碰撞
|
|
|
- // console.log(staveSection, 'staveSection out')
|
|
|
- staveSection.forEach((t) => {
|
|
|
- let shift_y = 0
|
|
|
- ;[...vfcurve, ...vfties, ...vfvoices].forEach((curve) => {
|
|
|
- const result = collisionDetection(t, curve)
|
|
|
- // console.log(result, 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.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)
|
|
|
- _vftexts.push(vftext as SVGAElement)
|
|
|
- }
|
|
|
- })
|
|
|
- if (maxY !== 0 && _vftexts.length > 1) {
|
|
|
- _vftexts.forEach((vftext) => {
|
|
|
- vftext.setAttribute('y', 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)
|
|
|
- }
|
|
|
- })
|
|
|
- })
|
|
|
-
|
|
|
- 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 + '')
|
|
|
- }
|
|
|
- } 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 + '')
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
- })
|
|
|
-
|
|
|
- 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'))) + '')
|
|
|
- }
|
|
|
- })
|
|
|
- })
|
|
|
- // 如果渐弱渐强有平行的文字
|
|
|
- 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 + '')
|
|
|
- }
|
|
|
- } else if (result.x2 > result.x1 + result.w1) {
|
|
|
- // 右
|
|
|
- if (Math.abs(result.y2 - result.y1) > 10) {
|
|
|
- text.setAttribute('y', 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 + '')
|
|
|
- }
|
|
|
- } 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 + '')
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- } 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 + '')
|
|
|
- }
|
|
|
- text2.setAttribute('x', result2.x1 + result2.w1 + 5 + '')
|
|
|
- if (Math.abs(result2.y2 - result2.y1) > 10) {
|
|
|
- text2.setAttribute('y', 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 + '')
|
|
|
- }
|
|
|
- } else {
|
|
|
- const result = collisionDetection(vftext as SVGAElement, text as SVGAElement)
|
|
|
- if (result.isCollision) {
|
|
|
- text.setAttribute('y', result.y1 + result.h1 + result.h2 + '')
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- setTimeout(() => resetGlobalText())
|
|
|
- }
|
|
|
- // 技巧文本
|
|
|
- const resetGlobalText = () => {
|
|
|
- if (!container.value) return
|
|
|
- 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,
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
expose({
|
|
|
setRender,
|
|
|
reRender,
|