소스 검색

绘制鼠标点击的轨迹

Michael Wang 4 년 전
부모
커밋
396ddf2df7
5개의 변경된 파일100개의 추가작업 그리고 23개의 파일을 삭제
  1. 84 21
      src/components/mark/MarkBody.vue
  2. 3 0
      src/components/mark/MarkDrawTrack.vue
  3. 1 1
      src/components/mark/MarkHistory.vue
  4. 11 0
      src/components/mark/store.ts
  5. 1 1
      src/types/index.ts

+ 84 - 21
src/components/mark/MarkBody.vue

@@ -6,7 +6,7 @@
         :key="index"
         class="single-image-container"
       >
-        <img :src="item.url" @click="makeMark" />
+        <img :src="item.url" @click="(event) => makeMark(event, item)" />
         <MarkDrawTrack
           :track-list="item.trackList"
           :original-image="item.originalImage"
@@ -24,10 +24,10 @@
 
 <script lang="ts">
 import { computed, defineComponent, reactive, ref, watchEffect } from "vue";
-import { store } from "./store";
+import { findCurrentTaskMarkResult, store } from "./store";
 import filters from "@/filters";
 import MarkDrawTrack from "./MarkDrawTrack.vue";
-import { Track } from "@/types";
+import { MarkResult, Track } from "@/types";
 
 interface SliceImage {
   url: string;
@@ -37,6 +37,7 @@ interface SliceImage {
   sliceImage: HTMLImageElement;
   dx: number;
   dy: number;
+  accumTopHeight: number;
 }
 export default defineComponent({
   name: "MarkBody",
@@ -44,7 +45,10 @@ export default defineComponent({
   setup(props, context) {
     const container = ref(null);
     let sliceImagesWithTrackList: Array<SliceImage> = reactive([]);
-    watchEffect(async () => {
+    let maxSliceWidth = 0;
+    let theFinalHeight = 0;
+
+    const renderPaperAndMark = async () => {
       async function loadImage(url: string): Promise<HTMLImageElement> {
         return new Promise((resolve, reject) => {
           const image = new Image();
@@ -56,18 +60,41 @@ export default defineComponent({
       }
       if (!store.currentTask?.libraryId) return;
 
+      // check if have MarkResult for currentTask
+      let markResult = findCurrentTaskMarkResult();
+      // console.log("watcheffect markResult 1", markResult, store.markResults);
+
+      if (!markResult) {
+        const { libraryId, studentId } = store.currentTask;
+        const statusValue = store.setting.statusValue;
+        markResult = {} as MarkResult;
+        markResult.libraryId = libraryId;
+        markResult.studentId = studentId;
+        markResult.statusValue = statusValue;
+        markResult.spent = Date.now();
+
+        markResult.trackList = store.currentTask.questionList.reduce(
+          (all, c) => all.concat(c.trackList),
+          [] as Array<Track>
+        );
+        store.markResults = [...store.markResults, markResult];
+        // console.log("watcheffect markResult 2", markResult, store.markResults);
+      }
+      // store.markResults.splice(store.markResults.indexOf(markResult), 1);
+      // store.markResults.push(markResult);
+      // console.log("watcheffect markResult 3", markResult, store.markResults);
+      // const allTrackList = findCurrentTaskMarkResult().trackList;
+      // console.log(allTrackList);
+      // console.log(store.markResults);
+
       // reset sliceImagesWithTrackList
       sliceImagesWithTrackList.splice(0);
-      const allTrackList = store.currentTask.questionList.reduce(
-        (all, c) => all.concat(c.trackList),
-        [] as Array<Track>
-      );
 
       if (store.currentTask.sliceConfig?.length) {
         for (const url of store.currentTask.sliceUrls) {
           await loadImage(filters.toCompleteUrl(url));
         }
-        const theFinalheight = store.currentTask.sliceConfig
+        theFinalHeight = store.currentTask.sliceConfig
           .map((v) => v.h)
           .reduce((acc, v) => (acc += v));
         let accumTopHeight = 0;
@@ -80,7 +107,7 @@ export default defineComponent({
           const image = await loadImage(url);
 
           const div = (container.value as unknown) as HTMLDivElement;
-          const maxSliceWidth = Math.max(
+          maxSliceWidth = Math.max(
             ...store.currentTask.sliceConfig.map((v) => v.w)
           );
 
@@ -103,7 +130,7 @@ export default defineComponent({
           );
           // console.log(image, canvas.height, sliceConfig, ctx);
           // console.log(canvas.toDataURL());
-          const thisImageTrackList = allTrackList.filter(
+          const thisImageTrackList = markResult.trackList.filter(
             (v) => v.offsetIndex === sliceConfig.i
           );
 
@@ -117,13 +144,14 @@ export default defineComponent({
             // 通过positionY来定位是第几张slice的还原,并过滤出相应的track
             trackList: thisImageTrackList.filter(
               (t) =>
-                t.positionY >= accumTopHeight / theFinalheight &&
-                t.positionY < accumBottomHeight / theFinalheight
+                t.positionY >= accumTopHeight / theFinalHeight &&
+                t.positionY < accumBottomHeight / theFinalHeight
             ),
             originalImage: image,
             sliceImage,
             dx: sliceConfig.x,
             dy: sliceConfig.y,
+            accumTopHeight,
           });
           accumTopHeight = accumBottomHeight;
         }
@@ -142,10 +170,10 @@ export default defineComponent({
           .filter((v) => v) as unknown) as Array<[number, number]>;
 
         const maxSplitConfig = Math.max(...store.setting.splitConfig);
-        const maxSliceWidth =
+        maxSliceWidth =
           Math.max(...images.map((v) => v.naturalWidth)) * maxSplitConfig;
 
-        const theFinalheight =
+        theFinalHeight =
           newConfig.length *
           images.reduce((acc, v) => (acc += v.naturalHeight), 0);
 
@@ -180,7 +208,7 @@ export default defineComponent({
             // console.log(image, canvas.height, sliceConfig, ctx);
             // console.log(canvas.toDataURL());
 
-            const thisImageTrackList = allTrackList.filter(
+            const thisImageTrackList = markResult.trackList.filter(
               (t) =>
                 t.offsetIndex === store.currentTask.sliceUrls.indexOf(url) + 1
             );
@@ -190,22 +218,34 @@ export default defineComponent({
             sliceImage.src = dataUrl;
             sliceImagesWithTrackList.push({
               url: canvas.toDataURL(),
-              indexInSliceUrls: store.currentTask.sliceUrls.indexOf(url),
+              indexInSliceUrls: store.currentTask.sliceUrls.indexOf(url) + 1,
               trackList: thisImageTrackList.filter(
                 (t) =>
-                  t.positionY >= accumTopHeight / theFinalheight &&
-                  t.positionY < accumBottomHeight / theFinalheight
+                  t.positionY >= accumTopHeight / theFinalHeight &&
+                  t.positionY < accumBottomHeight / theFinalHeight
               ),
               originalImage: image,
               sliceImage,
               dx: image.naturalWidth * config[0],
               dy: 0,
+              accumTopHeight,
             });
             accumTopHeight = accumBottomHeight;
           }
         }
       }
-    });
+    };
+
+    watchEffect(renderPaperAndMark);
+
+    // const reRenderPaperAndMark = () => {
+    //   // const markResult = findCurrentTaskMarkResult();
+    //   // const thisImageTrackList = markResult.trackList.filter(
+    //   //       (v) => v.offsetIndex === sliceConfig.i
+    //   //     );
+    //   sliceImagesWithTrackList;
+    // };
+    // watch(() => store.markResults, reRenderPaperAndMark, { deep: true });
 
     const answerPaperScale = computed(() => {
       // 放大、缩小不影响页面之前的滚动条定位
@@ -240,8 +280,31 @@ export default defineComponent({
       return scale * 100 + "%";
     });
 
-    const makeMark = (event: Event) => {
+    const makeMark = (event: MouseEvent, item: SliceImage) => {
       console.log(event);
+      console.log(item);
+      const target = event.target as HTMLImageElement;
+      const track = {} as Track;
+      // TODO: choose question first
+      track.mainNumber = 4;
+      track.subNumber = "1";
+      track.score = 9;
+      track.offsetIndex = item.indexInSliceUrls;
+      track.offsetX =
+        event.offsetX * (target.naturalWidth / target.width) + item.dx;
+      track.offsetY =
+        event.offsetY * (target.naturalHeight / target.height) + item.dy;
+      track.positionX = (track.offsetX - item.dx) / maxSliceWidth;
+      track.positionY =
+        (track.offsetY - item.dy + item.accumTopHeight) / theFinalHeight;
+      // console.log(track);
+      const markResult = findCurrentTaskMarkResult();
+      // console.log("makemark markresult", markResult);
+      if (markResult) {
+        markResult.trackList = [...markResult.trackList, track];
+      }
+      // sliceImagesWithTrackList.find(s => s.indexInSliceUrls === item.indexInSliceUrls)
+      item.trackList.push(track);
     };
     return {
       container,

+ 3 - 0
src/components/mark/MarkDrawTrack.vue

@@ -68,5 +68,8 @@ export default defineComponent({
   height: 200px;
   margin-top: -100px;
   margin-left: -100px;
+
+  /* to click through div */
+  pointer-events: none;
 }
 </style>

+ 1 - 1
src/components/mark/MarkHistory.vue

@@ -1,7 +1,7 @@
 <template>
   <div
     :style="{ display: store.historyOpen ? 'block' : 'none' }"
-    style="width: 300px"
+    style="width: 300px; border: 1px solid grey"
   >
     <div>
       <input

+ 11 - 0
src/components/mark/store.ts

@@ -44,6 +44,17 @@ export function toggleMode() {
   // 切换模式会清除当前任务的打分
 }
 
+export function findCurrentTaskMarkResult() {
+  const { libraryId, studentId } = store.currentTask;
+  const statusValue = store.setting.statusValue;
+  return store.markResults.find(
+    (m) =>
+      m.libraryId === libraryId &&
+      m.studentId === studentId &&
+      m.statusValue === statusValue
+  );
+}
+
 /** 给当前任务评分 */
 export function markScore() {}
 

+ 1 - 1
src/types/index.ts

@@ -135,7 +135,7 @@ export interface UISetting {
   "answer.paper.scale": number; // 0.2 gap
 }
 
-interface MarkResult {
+export interface MarkResult {
   libraryId: number;
   studentId: number;
   statusValue: string;