|
@@ -1,7 +1,14 @@
|
|
|
<template>
|
|
|
<template v-for="(track, index) in trackList" :key="index">
|
|
|
- <div class="score-container" :style="computeTopAndLeft(track)">
|
|
|
- <span class="tw-m-auto">
|
|
|
+ <div
|
|
|
+ class="score-container"
|
|
|
+ :class="[focusedTrack(track) && 'score-animation']"
|
|
|
+ :style="computeTopAndLeft(track)"
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ class="tw-m-auto"
|
|
|
+ :id="'a' + track.mainNumber + track.subNumber + track.offsetY"
|
|
|
+ >
|
|
|
{{ track.score }}
|
|
|
</span>
|
|
|
</div>
|
|
@@ -10,7 +17,7 @@
|
|
|
|
|
|
<script lang="ts">
|
|
|
import { Track } from "@/types";
|
|
|
-import { defineComponent, PropType } from "vue";
|
|
|
+import { defineComponent, PropType, watch } from "vue";
|
|
|
import { store } from "./store";
|
|
|
|
|
|
export default defineComponent({
|
|
@@ -25,6 +32,9 @@ export default defineComponent({
|
|
|
},
|
|
|
},
|
|
|
setup({ trackList, originalImage }) {
|
|
|
+ const focusedTrack = (track: Track) => {
|
|
|
+ return store.focusTracks.includes(track);
|
|
|
+ };
|
|
|
const computeTopAndLeft = (track: Track) => {
|
|
|
const topInsideSlice = track.offsetY;
|
|
|
const leftInsideSlice = track.offsetX;
|
|
@@ -34,6 +44,9 @@ export default defineComponent({
|
|
|
// offx: track.offsetX,
|
|
|
// offy: track.offsetY,
|
|
|
// });
|
|
|
+ // if (store.focusTracks.includes(track)) {
|
|
|
+ // console.log("has track");
|
|
|
+ // }
|
|
|
return {
|
|
|
top: (topInsideSlice / originalImage.naturalHeight) * 100 + "%",
|
|
|
left: (leftInsideSlice / originalImage.naturalWidth) * 100 + "%",
|
|
@@ -41,7 +54,33 @@ export default defineComponent({
|
|
|
};
|
|
|
};
|
|
|
|
|
|
- return { store, computeTopAndLeft };
|
|
|
+ watch(
|
|
|
+ () => store.focusTracks.length,
|
|
|
+ () => {
|
|
|
+ if (store.focusTracks.length === 0) return;
|
|
|
+ const minImageIndex = Math.min(
|
|
|
+ ...store.focusTracks.map((t) => t.offsetIndex)
|
|
|
+ );
|
|
|
+ const minImageOffsetY = Math.min(
|
|
|
+ ...store.focusTracks
|
|
|
+ .filter((t) => t.offsetIndex === minImageIndex)
|
|
|
+ .map((t) => t.offsetY)
|
|
|
+ );
|
|
|
+ const topTrack = store.focusTracks.find(
|
|
|
+ (t) =>
|
|
|
+ t.offsetIndex === minImageIndex && t.offsetY === minImageOffsetY
|
|
|
+ );
|
|
|
+ if (topTrack) {
|
|
|
+ document
|
|
|
+ .querySelector(
|
|
|
+ `#a${topTrack.mainNumber + topTrack.subNumber + topTrack.offsetY}`
|
|
|
+ )
|
|
|
+ ?.scrollIntoView();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ return { store, focusedTrack, computeTopAndLeft };
|
|
|
},
|
|
|
});
|
|
|
</script>
|
|
@@ -62,4 +101,22 @@ export default defineComponent({
|
|
|
/* to click through div */
|
|
|
pointer-events: none;
|
|
|
}
|
|
|
+.score-animation {
|
|
|
+ animation: 2s ease-in-out 0s infinite alternate change_color;
|
|
|
+}
|
|
|
+
|
|
|
+@keyframes change_color {
|
|
|
+ from {
|
|
|
+ color: red;
|
|
|
+ font-size: 2em;
|
|
|
+ margin-top: -100px;
|
|
|
+ margin-left: -100px;
|
|
|
+ }
|
|
|
+ to {
|
|
|
+ color: black;
|
|
|
+ font-size: 4em;
|
|
|
+ margin-top: -80px;
|
|
|
+ margin-left: -80px;
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|