|
@@ -1,129 +0,0 @@
|
|
|
-<template>
|
|
|
- <template v-for="(track, index) in trackList" :key="index">
|
|
|
- <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>
|
|
|
- </template>
|
|
|
- <template v-for="(tag, index) in specialTagList" :key="index">
|
|
|
- <div class="score-container" :style="computeTopAndLeft(tag)">
|
|
|
- <span class="tw-m-auto">
|
|
|
- {{ tag.tagName }}
|
|
|
- </span>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
-</template>
|
|
|
-
|
|
|
-<script lang="ts">
|
|
|
-import { SpecialTag, Track } from "@/types";
|
|
|
-import { defineComponent, PropType, watch } from "vue";
|
|
|
-import { store } from "./store";
|
|
|
-
|
|
|
-export default defineComponent({
|
|
|
- name: "MarkDrawTrack",
|
|
|
- props: {
|
|
|
- trackList: {
|
|
|
- type: Array as PropType<Array<Track>>,
|
|
|
- },
|
|
|
- specialTagList: {
|
|
|
- type: Array as PropType<Array<SpecialTag>>,
|
|
|
- },
|
|
|
- originalImage: {
|
|
|
- type: Object as PropType<HTMLImageElement>,
|
|
|
- required: true,
|
|
|
- },
|
|
|
- sliceImage: {
|
|
|
- type: Object as PropType<HTMLImageElement>,
|
|
|
- required: true,
|
|
|
- },
|
|
|
- dx: { type: Number, required: true },
|
|
|
- dy: { type: Number, required: true },
|
|
|
- },
|
|
|
- setup({ trackList, originalImage, sliceImage, dx, dy }) {
|
|
|
- const focusedTrack = (track: Track) => {
|
|
|
- return store.focusTracks.includes(track);
|
|
|
- };
|
|
|
- const computeTopAndLeft = (track: Track | SpecialTag) => {
|
|
|
- const topInsideSlice = track.offsetY - dy;
|
|
|
- const leftInsideSlice = track.offsetX - dx;
|
|
|
- return {
|
|
|
- top: (topInsideSlice / sliceImage.naturalHeight) * 100 + "%",
|
|
|
- left: (leftInsideSlice / sliceImage.naturalWidth) * 100 + "%",
|
|
|
- "font-size": store.setting.uiSetting["answer.paper.scale"] * 2.2 + "em",
|
|
|
- };
|
|
|
- };
|
|
|
-
|
|
|
- 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({ behavior: "smooth" });
|
|
|
- }
|
|
|
- }
|
|
|
- );
|
|
|
-
|
|
|
- return { store, focusedTrack, computeTopAndLeft };
|
|
|
- },
|
|
|
-});
|
|
|
-</script>
|
|
|
-
|
|
|
-<style scoped>
|
|
|
-.score-container {
|
|
|
- position: absolute;
|
|
|
- display: flex;
|
|
|
- place-content: center;
|
|
|
- color: red;
|
|
|
-
|
|
|
- /* to center score */
|
|
|
- width: 200px;
|
|
|
- height: 200px;
|
|
|
- margin-top: -100px;
|
|
|
- margin-left: -100px;
|
|
|
-
|
|
|
- /* 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>
|