瀏覽代碼

feat: 谱面音符颜色、小节背景色块、背景阴影效果、速度标签位置、作曲家&作词家样式和位置

TIANYONG 1 年之前
父節點
當前提交
385d2ec052

+ 31 - 1
src/helpers/customMusicScore.ts

@@ -263,6 +263,7 @@ export const resetFormate = () => {
 		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
@@ -532,8 +533,37 @@ export const resetFormate = () => {
 			}
 		};
 
+		// 给小节添加背景色
+		staves.forEach((stave: any) => {
+			const list = [
+				Array.from(stave?.querySelectorAll(".vf-clef") || []),
+				Array.from(stave?.querySelectorAll(".vf-keysignature") || []),
+				Array.from(stave?.getElementsByTagName("text") || []),
+			].flat();
+			try {
+				if (list.length) {
+					list.forEach((_el: any) => {
+						_el?.style?.setProperty("display", "none");
+					});
+				}
+			} catch (error) {}
+			const bbox = stave?.getBBox() || {};
+			const rect = `<rect class="vf-custom-bg" x="${bbox.x}" y="${bbox.y}" width="${bbox.width}" height="${bbox.height}" fill="#609FCF" />`
+			const rectBottom = `<rect class="vf-custom-bot" x="${bbox.x}" y="${bbox.y+bbox.height}" width="${bbox.width}" height="12" fill="#2B70A5" />`
+			const customG = `<g>${rect}${rectBottom}</g>`
+			try {
+				if (list.length) {
+					list.forEach((_el: any) => {
+						_el?.style?.removeProperty("display");
+					});
+				}
+			} catch (error) {}
+			stave.innerHTML = customG + stave.innerHTML;
+		});
+		
+		state.vfmeasures = state.vfmeasures.concat(vfmeasures);
 	}
-
+	
 	// setTimeout(() => this.resetGlobalText());
 };
 // 技巧文本

+ 15 - 1
src/helpers/formateMusic.ts

@@ -626,6 +626,8 @@ export const formatXML = (xml: string, xmlUrl?: string): string => {
 	const measures = Array.from(xmlParse.getElementsByTagName("measure"));
 	const repeats: any = Array.from(xmlParse.querySelectorAll('repeat'));
 	compatibleXmlPitchVoice(xmlParse);
+	// 获取作词、作曲家
+	getComposer(xmlParse);
 	// 处理重复小节信息
 	parseXmlToRepeat(repeats)
 	// 解析处理evxml
@@ -1280,6 +1282,18 @@ export const getNoteByMeasuresSlursStart = (note: any) => {
 	return activeNote;
 };
 
+// 解析xml,获取作词、作曲家名称
+const getComposer = (xmlParse: any) => {
+	const creators: any = Array.from(xmlParse.querySelectorAll('creator'));
+	for (const creator of creators) {
+		if (creator && creator.getAttribute('type') === 'composer' && !state.musicComposer) {
+			state.musicComposer = creator.textContent?.trim() || '';
+		}
+		if (creator && creator.getAttribute('type') === 'lyricist' && !state.musicLyricist) {
+			state.musicLyricist = creator.textContent?.trim() || '';
+		}
+	}
+}
 
 // 通过xml信息获取重播的小节信息
 const parseXmlToRepeat = (repeats: any) => {
@@ -1460,7 +1474,7 @@ const analyzeEvxml = (xmlParse: any, xmlUrl?: string) => {
  */
 export const compatibleXmlPitchVoice = (xmlParse: any) => {
 	const partNames = Array.from(xmlParse.getElementsByTagName('part-name'));
-	const partListNames = partNames.map((item: any) => item[0]?.textContent?.trim().toLocaleUpperCase !== "COMMON");
+	const partListNames = partNames.filter((item: any) => item?.textContent?.trim().toLocaleUpperCase() !== "COMMON");
 	if (partListNames.length == 1) {
 		const instrumentNames = Array.from(xmlParse.getElementsByTagName('instrument-name')) || [];
 		// @ts-ignore

+ 1 - 1
src/page-instrument/component/authorName/index.module.less

@@ -29,7 +29,7 @@
                 height: 20px;
                 padding: 0;
                 font-weight: 400;
-                font-size: 14px;
+                font-size: 13px;
                 color: #FFFFFF;
                 line-height: 20px;
                 .van-notice-bar__wrap{

+ 16 - 4
src/page-instrument/component/authorName/index.tsx

@@ -1,4 +1,4 @@
-import { defineComponent } from "vue"
+import { defineComponent, computed } from "vue"
 import styles from "./index.module.less"
 import { NoticeBar } from "vant"
 import state from "/src/state"
@@ -7,6 +7,11 @@ import { smoothAnimationState } from "../../view-detail/smoothAnimation"
 export default defineComponent({
    name: "authorName",
    setup() {
+		const combineAuthor = computed(() => {
+			const context = state.musicLyricist ? state.musicComposer + ' / ' + state.musicLyricist : state.musicComposer;
+			return context
+		});
+
       return () => (
          <>
             {
@@ -17,9 +22,16 @@ export default defineComponent({
                   </div>
                   <div class={styles.authorCon}>
                      <div class={styles.author}>
-                        <NoticeBar text={'作词:李非 '} background="none" />
-                        <NoticeBar text={'作曲:雅克兄弟'} background="none" />
-                        {/* <NoticeBar text={'作词:李非 / 作曲:雅克兄弟'} background="none" /> */}
+                        {
+                           state.isSingleLine ? 
+                           <>
+                              { state.musicLyricist && <NoticeBar text={state.musicLyricist} background="none" />}
+                              { state.musicComposer && <NoticeBar text={state.musicComposer} background="none" /> }                           
+                           </> : 
+                           <>
+                              { combineAuthor.value && <NoticeBar text={combineAuthor.value} background="none" /> }
+                           </>
+                        }
                      </div>
                   </div>
                </div>

+ 1 - 0
src/page-instrument/view-detail/index.tsx

@@ -423,6 +423,7 @@ export default defineComponent({
           {/* 曲谱渲染 */}
           {!detailData.isLoading && 
             <MusicScore 
+              musicColor={'#FFFFFF'}
               showPartNames={state.isCombineRender}
               onRendered={handleRendered} 
             > 

+ 3 - 3
src/page-instrument/view-detail/smoothAnimation/index.less

@@ -25,9 +25,9 @@
     #cursorImg-0 {
         display: none;
     }
-    .staveBox {
-        display: none !important;
-    }
+    // .staveBox {
+    //     display: none !important;
+    // }
     .authorName{
         position: fixed;
         left: 0;

+ 23 - 1
src/state.ts

@@ -489,6 +489,12 @@ const state = reactive({
   defaultModeType: 1,
   /** 音符最多歌词次数 */
   maxLyricNum: 0,
+  /** 小节dom集合 */
+  vfmeasures: [] as SVGAElement[],
+  /** 作曲家 */
+  musicComposer: '',
+  /** 作词家 */
+  musicLyricist: '',
 });
 const browserInfo = browser();
 let offset_duration = 0;
@@ -1518,4 +1524,20 @@ export const moveSvgDom = (skipNote?: boolean) => {
       behavior: "smooth",
     });
   }
-}
+}
+
+watch(
+	() => state.activeMeasureIndex,
+	() => {
+    console.log('当前小节',state.activeMeasureIndex)
+    state.vfmeasures.forEach((item: any, idx: number) => {
+      if (idx === (state.activeMeasureIndex-1)) {
+        item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#132D4C")
+        item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#040D1E")
+      } else {
+        item.querySelector('.vf-custom-bg')?.setAttribute("fill", "#609FCF")
+        item.querySelector('.vf-custom-bot')?.setAttribute("fill", "#2B70A5")
+      }
+    })
+	}
+);

+ 27 - 2
src/view/music-score/index.module.less

@@ -24,8 +24,8 @@
     }
     .noteActive {
         path {
-            fill: #FF2B29;
-            stroke: #FF2B29;
+            fill: #FFC121;
+            stroke: #FFC121;
         }
         transform-box: fill-box;
         transform-origin: center;
@@ -33,6 +33,31 @@
         // transform: scale(2);
         // transition: all 0.3s;
     }
+    .vf-custom-rect {
+        position: relative;
+        // stroke: grey;
+        // stroke-width: 5;
+        // box-shadow: 10px 10px 5px grey;
+        // &::before {
+        //     content: "";
+        //     position: absolute;
+        //     left: 0;
+        //     bottom: -10Px;
+        //     width: 100%;
+        //     height: 8Px;
+        //     background: linear-gradient(rgba(7, 24, 56, 0.5) 0%, #010D31 100%);
+        //     z-index: 0;
+        //     filter: blur(5Px);
+        //     opacity: 0.7;
+        // }        
+    }
+    .vf-custom-dom {
+        position: relative;
+        width: 200px;
+        height: 50px;
+        background: #FFC121;
+        z-index: 999;
+    }
 }
 .inGradualRange{
    :global{

+ 5 - 4
src/view/music-score/index.tsx

@@ -86,9 +86,10 @@ export default defineComponent({
 				autoResize: false,
 				followCursor: false,
 				drawPartNames: props.showPartNames, // 是否渲染声轨名称
-				// drawLyricist: false, // 渲染作曲家
-				// drawComposer: false, // 渲染作词家
+				drawLyricist: false, // 渲染作曲家
+				drawComposer: false, // 渲染作词家
 				defaultColorMusic: props.musicColor, // 颜色
+				// pageBackgroundColor: '#609FCF',
 				renderSingleHorizontalStaffline: state.isSingleLine ? true : false,
 				autoGenerateMultipleRestMeasuresFromRestMeasures: state.isSingleLine ? false : true, // 连续休止小节是否合并显示
 				// darkMode: true, // 暗黑模式
@@ -96,7 +97,7 @@ export default defineComponent({
 				// autoBeam: true,
 				// drawMetronomeMarks: false,
 				// ...this.opotions,
-				
+				colorStemsLikeNoteheads: true, // 是否将音符柄的颜色设置为与它们的音符头相同,默认false
 			});
 			// osmd.EngravingRules.CompactMode = true // 紧凑模式
 			// osmd.EngravingRules.PageRightMargin = state.isSingleLine ? (window.innerWidth+200)/10 : 2;
@@ -112,7 +113,7 @@ export default defineComponent({
 			// 	osmd.EngravingRules.PageRightMargin = 7;
 			// }
 			//osmd.EngravingRules.PageBottomMargin = state.platform === IPlatform.PC ? 1 : 2;
-			osmd.EngravingRules.PageBottomMargin = 0;
+			osmd.EngravingRules.PageBottomMargin = 5;
 			osmd.EngravingRules.DYMusicScoreType =
 				state.musicRenderType === EnumMusicRenderType.staff ? "staff" : "jianpu";
 			// 如果为固定调,需要加入全局

+ 15 - 0
src/view/selection/index.module.less

@@ -254,4 +254,19 @@
     width: 2px;
     height: 2px;
     // background: #07c160;
+}
+
+.staveBg {
+    &::before {
+        content: "";
+        position: absolute;
+        left: 0;
+        bottom: -10Px;
+        width: 100%;
+        height: 8Px;
+        background: linear-gradient(rgba(7, 24, 56, 0.5) 0%, #010D31 100%);
+        z-index: 0;
+        filter: blur(5Px);
+        opacity: 0.7;
+    }
 }

+ 2 - 1
src/view/selection/index.tsx

@@ -151,7 +151,7 @@ const calcNoteData = () => {
 			}
 		}
 	}
-	// console.log("🚀 ~ selectData.notes:", selectData.notes, selectData.staves);
+	console.log("🚀 ~ selectData.notes:", selectData.notes, selectData.staves);
 };
 
 /** 重新计算 */
@@ -262,6 +262,7 @@ export default defineComponent({
 										styles.position,
 										showClass.value(item),
 										scoreItem ? `scoreItemLeve${scoreItem.leve}` : "",
+										item.multipleRestMeasures <= 1 ? styles.staveBg : "",
 										(state.platform === IPlatform.PC && state.zoom > 0.8) ? styles.linePC : '',
 									]}
 									style={item.staveBox}