Browse Source

横向指法

liushengqiang 2 năm trước cách đây
mục cha
commit
370ad9e852

+ 0 - 1
src/page-gym/App.tsx

@@ -34,7 +34,6 @@ export default defineComponent({
 				setToken(query.Authorization);
 			}
 			setUser();
-			document.getElementById('loading')!.className = ''
 			localStorage.setItem("behaviorId", getRandomKey());
 		});
 

+ 29 - 21
src/page-gym/detail/index.module.less

@@ -11,44 +11,52 @@
 }
 
 .detail {
-    display: flex;
-    flex-direction: column;
     width: 100vw;
     height: 100vh;
     overflow: hidden;
     background-color: var(--van-primary-color);
-    &.opencamera{
+    --header-height: 62px;
+    --fingerin-bottom: 0;
+    --fingerin-right: 0;
+    &.opencamera {
         opacity: .7;
     }
 
     .headHeight {
-        height: 62px;
+        height: var(--header-height);
+    }
+
+    .fingeringHeight {
+        position: relative;
+        height: var(--fingerin-bottom);
     }
 
     .container {
         position: relative;
-        margin: 0 18px 18px 18px;
-        flex: 1;
-        overflow-y: auto;
-        border-radius: 10px;
+        height: calc(100vh - 18px - var(--header-height));
+        margin: 0 18px;
         background: var(--container-background);
-        &::-webkit-scrollbar {
-            width: 0;
-            display: none;
-        }
+        border-radius: 10px;
+        overflow: hidden;
+        padding-bottom: var(--fingerin-bottom);
+        padding-right: var(--fingerin-right);
     }
-
-    
 }
-.plugins{
-    position: fixed;
-    z-index: -100;
-    bottom: -100%;
-    left: -100%;
+
+.plugins {
+    display: none;
 }
 
 :global {
-    #musicAndSelection {
-        position: relative;
+    #cursorImg-0 {
+        min-height: 58PX;
+        content: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
+        margin-top: -14PX;
+        border-radius: 2px;
+        background-image: var(--cursor-color);
+        background-repeat: repeat-y;
+        background-position-x: 50%;
+        opacity: var(--corsor-opacity);
     }
+
 }

+ 30 - 22
src/page-gym/detail/index.tsx

@@ -1,6 +1,6 @@
 import queryString from "query-string";
 import { Skeleton } from "vant";
-import { defineComponent, onBeforeMount, onMounted, reactive, Transition } from "vue";
+import { computed, defineComponent, onBeforeMount, onMounted, reactive, Transition } from "vue";
 import { useRoute } from "vue-router";
 import { formateTimes } from "../../helpers/formateMusic";
 import Metronome, { metronomeData } from "../../helpers/metronome";
@@ -35,8 +35,6 @@ export default defineComponent({
 		const paramsId = route.params.id as string;
 		const detailData = reactive({
 			isLoading: true,
-			svgRendered: false, // 曲谱渲染完成
-			showSelection: false, // 可以加载点击浮层
 			paddingLeft: "",
 		});
 		const getAPPData = async () => {
@@ -141,11 +139,12 @@ export default defineComponent({
 				getCategory(values[0]);
 				getMusicInfo(values[1]);
 			});
+			document.getElementById("loading")!.className = "";
 		});
 
 		/** 渲染完成 */
 		const handleRendered = (osmd: any) => {
-			detailData.svgRendered = true;
+			state.musicRendered = true;
 			state.osmd = osmd;
 			state.times = formateTimes(osmd);
 			console.log("🚀 ~ state.times:", state.times);
@@ -153,26 +152,29 @@ export default defineComponent({
 				metronomeData.metro = new Metronome();
 				metronomeData.metro.init(state.times);
 			} catch (error) {}
-			detailData.showSelection = true;
 		};
+		/** 指法配置 */
+		const fingerConfig = computed(() => {
+			if (state.setting.displayFingering && state.fingeringInfo?.name) {
+				return {
+					"--fingerin-bottom": state.fingeringInfo.direction === "vertical" ? "" : "1.6rem",
+				};
+			}
+			return {};
+		});
 		return () => (
-			<div class={[styles.detail, state.setting.camera && styles.opencamera]} style={{ paddingLeft: detailData.paddingLeft }}>
-				{!detailData.svgRendered && (
+			<div class={[styles.detail, state.setting.camera && styles.opencamera]} style={{ paddingLeft: detailData.paddingLeft, ...fingerConfig.value }}>
+				{!state.musicRendered && (
 					<div class={styles.skeleton}>
 						<Skeleton class={styles.skeleton} row={8} />
 					</div>
 				)}
 				<div class={styles.headHeight}>
-					<Transition name="van-slide-down">{detailData.svgRendered && <HeaderTop />}</Transition>
+					<Transition name="van-slide-down">{state.musicRendered && <HeaderTop />}</Transition>
 				</div>
-				<div class={[styles.container, state.setting.eyeProtection && "eyeProtection", !state.setting.displayCursor && "hideCursor"]} id="mainContainer">
-					{/* 曲谱渲染和点击层 */}
-					{!detailData.isLoading && (
-						<div id="musicAndSelection">
-							<MusicScore onRendered={handleRendered} />
-							{detailData.showSelection && <Selection />}
-						</div>
-					)}
+				<div class={[styles.container, state.setting.eyeProtection && "eyeProtection", !state.setting.displayCursor && "hideCursor"]}>
+					{/* 曲谱渲染 */}
+					{!detailData.isLoading && <MusicScore onRendered={handleRendered} />}
 					{/* 播放 */}
 					{!detailData.isLoading && <AudioList />}
 					{/* 评测 */}
@@ -183,15 +185,21 @@ export default defineComponent({
 						</>
 					)}
 					{/* 指法 */}
-					{/* {state.setting.displayFingering && <Fingering />} */}
+					{state.setting.displayFingering && state.fingeringInfo?.name && (
+						<div class={styles.fingeringHeight} style={{ height: state.fingeringInfo.direction === "vertical" ? 0 : "" }}>
+							<Fingering />
+						</div>
+					)}
 				</div>
 
 				{/* 公用的插件 */}
-				{detailData.svgRendered && (
-					<div class={styles.plugins}>
-						<MeasureSpeed />
-					</div>
-				)}
+				<div class={styles.plugins}>
+					{state.musicRendered && (
+						<>
+							<MeasureSpeed />
+						</>
+					)}
+				</div>
 			</div>
 		);
 	},

+ 10 - 9
src/state.ts

@@ -5,11 +5,14 @@ import _event, { EventEnum } from "./helpers/eventemitter";
 import { metronomeData } from "./helpers/metronome";
 import { GradualNote, GradualTimes, GradualVersion, IMode } from "./type";
 import { handleEndBegin, sendEvaluatingOffsetTime } from "./view/evaluating";
+import { IFingering } from "src/view/fingering/fingering-config";
 
 /** 入门 | 进阶 | 大师 */
 export type IDifficulty = "BEGINNER" | "ADVANCED" | "PERFORMER";
 
 const state = reactive({
+	/**曲谱是否渲染完成 */
+	musicRendered: false,
 	/** 当前曲谱数据ID, 和曲谱ID不一致 */
 	detailId: "",
 	/** 曲谱资源URL */
@@ -97,7 +100,7 @@ const state = reactive({
 		/** 循环播放 */
 		repeatAutoPlay: true,
 		/** 显示指法 */
-		displayFingering: false,
+		displayFingering: true,
 		/** 显示光标 */
 		displayCursor: true,
 		/** 频率 */
@@ -112,9 +115,7 @@ const state = reactive({
 	/** 节拍器的时间 */
 	fixtime: 0,
 	/** 指法信息 */
-	fingeringInfo: {
-
-	},
+	fingeringInfo: {} as IFingering,
 
 	repeatedBeats: 0,
 
@@ -241,7 +242,7 @@ export const skipNotePlay = (itemIndex: number, isStart = false) => {
 	if (isStart) {
 		itemTime = 0;
 	}
-	console.log("🚀 ~ itemTime:", itemTime);
+	// console.log("🚀 ~ itemTime:", itemTime);
 	if (item) {
 		state.songEl && (state.songEl.currentTime = itemTime);
 		state.backgroundEl && (state.backgroundEl.currentTime = itemTime);
@@ -405,15 +406,15 @@ export const handleSelection = (item: any) => {
  */
 export const scrollViewNote = () => {
 	const cursorElement = document.getElementById("cursorImg-0")!;
-	const mainContainer = document.getElementById("mainContainer")!;
-	if (!cursorElement && !mainContainer) return;
+	const musicAndSelection = document.getElementById("musicAndSelection")!;
+	if (!cursorElement && !musicAndSelection) return;
 	if (cursorElement.offsetTop > 50) {
-		mainContainer.scrollTo({
+		musicAndSelection.scrollTo({
 			top: cursorElement.offsetTop - 25,
 			behavior: "smooth",
 		});
 	} else {
-		mainContainer.scrollTo({
+		musicAndSelection.scrollTo({
 			top: 0,
 			behavior: "smooth",
 		});

+ 1 - 1
src/view/audio-list/index.module.less

@@ -3,5 +3,5 @@
     left: 0;
     bottom: 0;
     width: 100%;
-    z-index: 1000;
+    z-index: -1000;
 }

+ 9 - 9
src/view/fingering/fingering-config.ts

@@ -1,15 +1,15 @@
 import { CSSProperties } from "vue";
 import relationships from "./fingering-relationships";
 
-export type Fingering = {
+export type ITypeFingering = {
 	json: any;
-	relationship: Object;
+	relationship: any;
 	height?: number | string;
 	width?: number | string;
 	maxWidth?: number;
 	styles?: CSSProperties;
 } | null;
-export type ITypeContentItem = {
+export type IFingering = {
 	name: IVocals;
 	direction: "vertical" | "transverse";
 	width?: string;
@@ -18,7 +18,7 @@ export type ITypeContentItem = {
 };
 
 type ITypeContent = {
-	[key: string | number]: ITypeContentItem;
+	[key: string | number]: IFingering;
 };
 
 export type IVocals = "flute" | "clarinet" | "saxophone" | "trumpet" | "horn" | "trombone" | "up-bass-horn" | "small-drum" | "tuba" | "piccolo";
@@ -94,7 +94,7 @@ export const subjectFingering: ITypeContent = {
 	}, // 短笛
 };
 
-export const getFingeringConfig = async (type: IVocals): Promise<Fingering> => {
+export const getFingeringConfig = async (type: IVocals): Promise<ITypeFingering> => {
 	switch (type) {
 		case "flute":
 			const flute = await import(`./fingering-img/flute/index.json`);
@@ -145,19 +145,19 @@ export const getFingeringConfig = async (type: IVocals): Promise<Fingering> => {
 			const upBassHorn = await import(`./fingering-img/up-bass-horn/index.json`);
 			return {
 				json: upBassHorn.default,
-				relationship: relationships.upBassHorn,
+				relationship: relationships["up-bass-horn"],
 			};
 		case "trombone":
 			const trombone = await import(`./fingering-img/trombone/index.json`);
 			return {
 				json: trombone.default,
-				relationship: relationships.trombone,
+				relationship: relationships["trombone"],
 			};
 		case "saxophone":
 			const saxophone = await import(`./fingering-img/saxophone/index.json`);
 			return {
 				json: saxophone.default,
-				relationship: relationships.saxophone,
+				relationship: relationships["saxophone"],
 				styles: {
 					marginLeft: ".2rem",
 					marginRight: ".3rem",
@@ -167,7 +167,7 @@ export const getFingeringConfig = async (type: IVocals): Promise<Fingering> => {
 			const smallDrum = await import(`./fingering-img/small-drum/index.json`);
 			return {
 				json: smallDrum.default,
-				relationship: relationships.smallDrum,
+				relationship: relationships["up-bass-horn"],
 				width: "180px",
 			};
 		default:

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
src/view/fingering/fingering-img/trombone/index.json


+ 2 - 2
src/view/fingering/fingering-relationships.ts

@@ -151,7 +151,7 @@ const relationships = {
     83: [0, 2],
     84: [0, ],
   },
-  upBassHorn: {
+  "up-bass-horn": {
     0: [1, 2, 3],
     40: [4, 5, 6],
     41: [4, 2, 6],
@@ -318,7 +318,7 @@ const relationships = {
     97: [1, 2, 3, 4, 5, 77, 88],
     98: [1, 2, 4, 5, 77, 8],
   },
-  smallDrum: {
+  "small-drum": {
     0: ['active', 'active-left', 'active-right'],
     64: ['left', 'right']
   }

+ 41 - 65
src/view/fingering/index.module.less

@@ -1,80 +1,56 @@
-.container{
-  img{
-    width: 100%;
-    margin: auto;
+.fingeringContainer{
+  position: absolute;
+  left: 0;
+  bottom: 0;
+  width: 100%;
+  height: 100%;
+  display: flex;
+  justify-content: space-evenly;
+  align-items: center;
+  padding: 0 10px;
+}
+.imgs{
+  position: relative;
+  width: 84%;
+  height: 100%;
+  & > img {
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -50%);
     display: block;
+    max-width: 100%;
+    max-height: 100%;
   }
 }
-.changeIndex{
-  position: absolute;
-  right: 35px;
-  bottom: 20px;
-  z-index: 10;
+.yidiao{
+  width: 30px;
+  color: var(--van-primary-color);
+  font-size: 12Px;
+  text-align: center;
+  opacity: 0;
+}
+.tizhi{
   width: 30px;
   height: 30px;
-  border-radius: 100%;
-  background-color: rgb(1, 193, 181);
-  line-height: 30px;
   text-align: center;
+  line-height: 30px;
+  border-radius: 100%;
+  background-color: var(--van-primary-color);
   color: #fff;
   box-shadow: 0 0 10px rgba(0, 0, 0, .05);
-}
-
-:global(.transverse) {
-  .changeIndex{
-    bottom: 10px;
-    right: 1px;
+  font-size: 12Px;
+  opacity: 0;
+  pointer-events: none;
+  &:active{
+    opacity: .8;
   }
 }
-
-:global(.flute) {
-  .changeIndex{
-    right: 2vw;
-    bottom: 2vh;
-    // right: -45px!important;
-  }
+.canDisplay{
+  opacity: 1;
+  pointer-events: initial;
 }
 
-:global(.piccolo) {
-  .changeIndex{
-    right: 1.5vw;
-    bottom: 20px;
-  }
-}
-
-:global(.clarinet) {
-  .changeIndex{
-    right: 2vw;
-  }
-}
-
-:global(.horn) {
-  .changeIndex{
-    right: 1vw;
-    bottom: 1.5vh;
-  }
-}
-
-:global(.up-bass-horn) {
-  .changeIndex{
-    left: 1vw;
-  }
-}
-
-:global(.tuba) {
-  .changeIndex{
-    right: inherit;
-    left: 1vw;
-    bottom: 20px;
-  }
-}
-
-:global(.saxophone) {
-  .changeIndex{
-    right: 1vw;
-    bottom: 1vh;
-  }
-}
 
 @keyframes activeopacity {
   0%   {transforopacitym: 0;}

+ 34 - 114
src/view/fingering/index.tsx

@@ -1,6 +1,7 @@
-import { defineComponent, onMounted, Ref, ref, toRefs } from "vue";
+import { computed, defineComponent, onBeforeMount, onMounted, reactive, Ref, ref, toRefs } from "vue";
 import styles from "./index.module.less";
 import state from "/src/state";
+import { getFingeringConfig, ITypeFingering } from "./fingering-config";
 
 export const getImageSize = (src: string): Promise<HTMLImageElement> => {
 	return new Promise((resolve, reject) => {
@@ -45,127 +46,46 @@ export const useFingeringSrc = (activeType: any, fingeringName: string, formatFi
 
 export default defineComponent({
 	name: "fingering",
-	props: {
-		type: {
-			type: String,
-			default: "",
-		},
-		fixedKey: {
-			type: Number,
-			default: 0,
-		},
-		fingeringInfo: {
-			type: Object,
-		},
-		loaded: {
-			type: Function,
-			default: () => {},
-		},
-		viewInfo: {
-			type: Object,
-		},
-	},
 	setup(props, { expose }) {
-    const fingeringInfo = state.fingeringInfo;
-    console.log("🚀 ~ fingeringInfo:", fingeringInfo)
-		const refProps = toRefs(props);
-		const container: Ref<HTMLDivElement | null> = ref(null);
-		const imgRef: Ref<HTMLImageElement | null> = ref(null);
-		const containerWidth = ref(0);
-		const index = ref(0);
-
-		// 横向具体指法样式
-		const ItemImgStyleTransverse = {
-			top: "50%",
-			left: "50%",
-			transform: "translate(-50%, -50%)",
-		};
-
-		// 竖向具体指法样式
-		const ItemImgStyleVertical = {
-			top: "50%",
-			left: 0,
-			// transform: 'translateY(-50%)',
+		const fingerData = reactive({
+			relationshipIndex: 0,
+			subject: null as unknown as ITypeFingering,
+		});
+		const getFingeringData = async () => {
+			fingerData.subject = await getFingeringConfig(state.fingeringInfo.name);
+			console.log("🚀 ~ fingerData.relationship:", fingerData.subject);
 		};
+		onBeforeMount(() => {
+			getFingeringData();
+		});
 
-		expose({
-			container,
-			containerWidth,
+		/** 当前音域 */
+		const realKey = computed(() => {
+			return state.times[state.activeNoteIndex]?.realKey || -1;
 		});
 
 		return () => {
-			if (!refProps.viewInfo.value?.activeType) return null;
-			const usedFixedKey = formatFixedKey(props.fingeringInfo?.name, refProps.fixedKey.value).value;
-			// console.log(refProps.fixedKey.value, usedFixedKey)
-			const relationshipGroup = formatRelationship(refProps.viewInfo.value?.activeType?.relationship, usedFixedKey || 0);
-
-			// console.log(imgRef.value?.width, imgRef.value?.offsetLeft, imgRef.value?.offsetTop)
-
-			const changeIndex = () => {
-				let nextIndex = index.value === relationshipGroup.length - 1 ? 0 : index.value + 1;
-				index.value = nextIndex;
-			};
-
-			const rs = relationshipGroup[index.value] || [];
+			const relationship = fingerData.subject?.relationship?.[realKey.value] || [];
+			const rs: number[] = Array.isArray(relationship[1]) ? relationship[fingerData.relationshipIndex] : relationship;
+			const canTizhi = Array.isArray(relationship[1]);
 			return (
-				<div
-					ref={container}
-					class={[props.fingeringInfo?.name, styles.container]}
-					style={{
-						width: props.fingeringInfo?.direction === "vertical" ? props.fingeringInfo?.width : "",
-						height: "100%",
-						display: "flex",
-						paddingLeft: props.fingeringInfo?.direction === "vertical" ? props.fingeringInfo?.paddingLeft : "",
-						paddingRight: props.fingeringInfo?.direction === "vertical" ? props.fingeringInfo?.paddingRight : "",
-					}}
-				>
-					{rs.includes(0) ? (
-						<span
-							style={{
-								position: "absolute",
-								top: ".5vh",
-								right: ".5vw",
-								color: "rgb(1, 193, 181)",
-								fontWeight: "bold",
-							}}
-						>
-							转调
-						</span>
-					) : null}
-					<img
-						ref={imgRef}
-						src={refProps.viewInfo.value?.fullsrc}
-						style={{
-							width: "auto",
-							maxWidth: "100%",
-							maxHeight: "100%",
-						}}
-					/>
-					{rs.map((key: number | string, index: number) => {
-						const nk: string = typeof key === "string" ? key.replace("active-", "") : String(key);
-						return (
-							<img
-								data-index={nk}
-								style={{
-									position: "absolute",
-									top: imgRef.value?.offsetTop + "px",
-									left: imgRef.value?.offsetLeft + "px",
-									zIndex: index,
-									height: imgRef.value?.height + "px",
-									width: imgRef.value?.width + "px",
-									maxWidth: "100%",
-									maxHeight: "100%",
-								}}
-								src={refProps.viewInfo.value?.activeType?.json?.[nk]}
-							/>
-						);
-					})}
+				<div class={[styles.fingeringContainer]}>
+					<span class={[styles.yidiao, !rs.includes(0) && styles.canDisplay]}>转调</span>
+
+					<div class={styles.imgs}>
+						<img src={fingerData.subject?.json?.full} />
+						{rs.map((key: number | string, index: number) => {
+							const nk: string = typeof key === "string" ? key.replace("active-", "") : String(key);
+							return <img data-index={nk} src={fingerData.subject?.json?.[nk]} />;
+						})}
+					</div>
 
-					{relationshipGroup.length > 1 ? (
-						<div onClick={changeIndex} class={styles.changeIndex}>
-							替指
-						</div>
-					) : null}
+					<div
+						class={[styles.tizhi, canTizhi && styles.canDisplay]}
+						onClick={() => (fingerData.relationshipIndex = fingerData.relationshipIndex === 0 ? 1 : 0)}
+					>
+						替指
+					</div>
 				</div>
 			);
 		};

+ 10 - 13
src/view/music-score/index.module.less

@@ -1,16 +1,13 @@
-.box {
-    :global {
-        #cursorImg-0 {
-            min-height: 58PX;
-            content: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
-            margin-top: -14PX;
-            border-radius: 2px;
-            background-image: var(--cursor-color);
-            background-repeat: repeat-y;
-            background-position-x: 50%;
-            opacity: var(--corsor-opacity);
+:global {
+    #musicAndSelection {
+        position: relative;
+        overflow-x: hidden;
+        overflow-y: auto;
+        height: 100%;
+        max-height: 100vh;
+        &::-webkit-scrollbar {
+            width: 0;
+            display: none;
         }
-
     }
-
 }

+ 25 - 25
src/view/music-score/index.tsx

@@ -1,26 +1,27 @@
-import { Skeleton } from "vant";
-import { defineComponent, nextTick, onBeforeMount, reactive } from "vue";
+import { defineComponent, onBeforeMount, reactive, ref } from "vue";
 import { formatXML, onlyVisible } from "../../helpers/formateMusic";
-import state from "../../state";
-import styles from "./index.module.less";
 // // @ts-ignore
 import { OpenSheetMusicDisplay } from "/osmd-extended/src";
+import state from "/src/state";
+import Selection from "../selection";
+import "./index.module.less"
 
 export default defineComponent({
 	name: "music-score",
 	emits: ["rendered"],
-	setup(prop, {emit}) {
+	setup(prop, { emit }) {
 		const musicData = reactive({
+			showSelection: false, // 可以加载点击浮层
 			isRenderLoading: true,
-            score: ''
+			score: "",
 		});
 		const getXML = async () => {
 			const res = await fetch(state.xmlUrl).then((response) => response.text());
-            const xml = formatXML(res)
+			const xml = formatXML(res);
 			musicData.score = onlyVisible(xml, state.partIndex);
 		};
 		const init = async () => {
-			const container: HTMLElement = document.querySelector("#musicContainer")!;
+			const container = document.getElementById('musicAndSelection')
 			// console.log("🚀 ~ container:", container);
 			if (!container || !musicData.score) return;
 			const osmd = new OpenSheetMusicDisplay(container, {
@@ -35,26 +36,25 @@ export default defineComponent({
 				// drawMetronomeMarks: false,
 				// drawLyricist: false,
 				// ...this.opotions,
-			}, );
-            
-            // osmd.EngravingRules.CompactMode = true // 紧凑模式
-            osmd.EngravingRules.PageRightMargin = 2
-            osmd.EngravingRules.PageTopMargin = 2
-            osmd.EngravingRules.PageLeftMargin = 2
-            osmd.EngravingRules.PageBottomMargin = 2
-            await osmd.load(musicData.score)
-            osmd.zoom = state.zoom
-            osmd.render()
-            // console.log("🚀 ~ osmd:", osmd)
-            emit('rendered', osmd)
+			});
+
+			// osmd.EngravingRules.CompactMode = true // 紧凑模式
+			osmd.EngravingRules.PageRightMargin = 2;
+			osmd.EngravingRules.PageTopMargin = 2;
+			osmd.EngravingRules.PageLeftMargin = 2;
+			osmd.EngravingRules.PageBottomMargin = 2;
+			await osmd.load(musicData.score);
+			osmd.zoom = state.zoom;
+			osmd.render();
+			// console.log("🚀 ~ osmd:", osmd)
+			emit("rendered", osmd);
+			musicData.showSelection = true;
 		};
 		onBeforeMount(async () => {
 			await getXML();
-            await init();
-            musicData.isRenderLoading = false;
+			await init();
+			musicData.isRenderLoading = false;
 		});
-		return () => (
-			<div id="musicContainer" class={styles.box}></div>
-		);
+		return () => <div id="musicAndSelection">{musicData.showSelection && <Selection />}</div>;
 	},
 });

+ 1 - 1
src/view/selection/index.module.less

@@ -96,7 +96,7 @@
 
 :global {
     .lineHide {
-        opacity: 0;
+        opacity: 0 !important;
     }
 }
 

+ 12 - 7
src/view/selection/index.tsx

@@ -13,7 +13,7 @@ export default defineComponent({
 			staves: [] as any[],
 		});
 		const calcNoteData = () => {
-			const musicContainer = document.getElementById("musicContainer")?.getBoundingClientRect() || { x: 0, y: 0 };
+			const musicContainer = document.getElementById("musicAndSelection")?.getBoundingClientRect() || { x: 0, y: 0 };
 			const parentLeft = musicContainer.x || 0;
 			const parentTop = musicContainer.y || 0;
 			const notes = state.times;
@@ -29,17 +29,22 @@ export default defineComponent({
 					staveBox: null as any,
 				};
 				if (!notesList.includes(item.noteId)) {
+					let staveBbox: any = {}
+					if (item.stave?.attrs?.id) {
+						const staveEle = document.querySelector(`#${item.stave.attrs.id}`);
+						staveBbox = staveEle?.parentElement?.parentElement?.getBoundingClientRect?.() || { x: 0, width: 0 };
+						// console.log("🚀 ~ staveBbox:", staveBbox)
+					}
 					if (item.svgElement) {
 						const noteEle = document.querySelector(`#vf-${item.svgElement?.attrs?.id}`);
-						const noteEleBox = item.svgElement.getBoundingBox?.() || { h: 40 };
-						// console.log("🚀 ~ noteEle:", noteEle, item.svgElement, noteEleBox.h)
+						
 						if (noteEle) {
 							const noteBbox = noteEle.getBoundingClientRect?.() || { x: 0, width: 0 };
 							noteItem.bbox = {
-								left: noteBbox.x - parentLeft + "px",
-								top: noteBbox.y - parentTop + "px",
-								width: noteBbox.width + "px",
-								height: noteEleBox.h * state.zoom + "px",
+								left: noteBbox.x - parentLeft - noteBbox.width / 4 + "px",
+								top: staveBbox.y - parentTop + "px",
+								width: noteBbox.width * 1.5 + "px",
+								height: staveBbox.height + "px",
 							};
 						}
 						selectData.notes.push(noteItem);

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác