zhangjie 1 年之前
父節點
當前提交
47e655ef8e

+ 175 - 18
src/features/check/CommonMarkBody.vue

@@ -17,28 +17,50 @@
         :style="{ width: answerPaperScale }"
         :class="[`rotate-board-${rotateBoard}`]"
       >
-        <div
+        <template
           v-for="(item, index) in sliceImagesWithTrackList"
           :key="index"
-          class="single-image-container"
         >
-          <img
-            :src="item.url"
-            draggable="false"
-            @click="(event) => innerMakeTrack(event, item)"
-            @contextmenu="showBigImage"
-          />
-          <MarkDrawTrack
-            :trackList="item.trackList"
-            :specialTagList="item.tagList"
-            :sliceImageHeight="item.originalImageHeight"
-            :sliceImageWidth="item.originalImageWidth"
-            :dx="item.dx"
-            :dy="item.dy"
-            @deleteSpecialtag="(tag) => deleteSpecialtag(item, tag)"
-          />
+          <div class="single-image-container">
+            <img
+              :src="item.url"
+              draggable="false"
+              @click="(event) => innerMakeTrack(event, item)"
+              @contextmenu="showBigImage"
+            />
+            <MarkDrawTrack
+              :trackList="item.trackList"
+              :specialTagList="item.tagList"
+              :sliceImageHeight="item.originalImageHeight"
+              :sliceImageWidth="item.originalImageWidth"
+              :dx="item.dx"
+              :dy="item.dy"
+              @delete-specialtag="(tag) => deleteSpecialtag(item, tag)"
+              @click-specialtag="(event) => clickSpecialtag(event, item)"
+            />
+            <div
+              v-if="isCustomSpecialTag"
+              class="image-canvas"
+              v-ele-move-directive.stop.prevent="{
+                moveStart: (event) => specialMouseStart(event, item),
+                moveElement: specialMouseMove,
+                moveStop: specialMouseStop,
+              }"
+            >
+              <template v-if="curSliceImagesWithTrackItem?.url === item.url">
+                <div
+                  v-if="store.currentSpecialTagType === 'LINE'"
+                  :style="specialLenStyle"
+                ></div>
+                <div
+                  v-if="store.currentSpecialTagType === 'CIRCLE'"
+                  :style="specialCircleStyle"
+                ></div>
+              </template>
+            </div>
+          </div>
           <hr class="image-seperator" />
-        </div>
+        </template>
       </div>
       <div v-else-if="store.isMultiMedia">
         <MultiMediaMarkBody />
@@ -61,6 +83,8 @@ import "viewerjs/dist/viewer.css";
 import Viewer from "viewerjs";
 import { message } from "ant-design-vue";
 import EventBus from "@/plugins/eventBus";
+import { vEleMoveDirective } from "../mark/use/eleMove";
+
 type MakeTrack = (
   event: MouseEvent,
   item: SliceImage,
@@ -99,6 +123,16 @@ const deleteSpecialtag = (item, tag) => {
   if (stagIndex === -1) return;
   store.currentTaskEnsured.markResult.specialTagList.splice(tagIndex, 1);
 };
+const clickSpecialtag = (event: MouseEvent, item: SliceImage) => {
+  // console.log(event);
+  const e = {
+    target: event.target.offsetParent.childNodes[0],
+    offsetX: event.offsetX + event.target.offsetLeft,
+    offsetY: event.offsetY + event.target.offsetTop,
+  };
+
+  makeTrack(e as MouseEvent, item, maxImageWidth, theFinalHeight);
+};
 
 const clearEmptySpecialTag = (item) => {
   item.tagList
@@ -402,6 +436,118 @@ const innerMakeTrack = (event: MouseEvent, item: SliceImage) => {
 };
 //#endregion : 评分
 
+//#region : 特殊标记:画线、框
+const isCustomSpecialTag = $computed(() => {
+  return ["CIRCLE", "LINE"].includes(store.currentSpecialTagType);
+});
+
+let specialPoint = $ref({ x: 0, y: 0, ex: 0, ey: 0 });
+let curImageTarget: HTMLElement = null;
+let curSliceImagesWithTrackItem: SliceImage = $ref(null);
+
+const specialLenStyle = $computed(() => {
+  if (specialPoint.ex <= specialPoint.x) return { display: "none" };
+
+  const width =
+    specialPoint.ex > specialPoint.x ? specialPoint.ex - specialPoint.x : 0;
+  return {
+    top: specialPoint.y + "px",
+    left: specialPoint.x + "px",
+    width: width + "px",
+    position: "absolute",
+    borderTop: "1px solid red",
+    zIndex: 9,
+  };
+});
+const specialCircleStyle = $computed(() => {
+  if (specialPoint.ex <= specialPoint.x || specialPoint.ey <= specialPoint.y)
+    return { display: "none" };
+
+  const width =
+    specialPoint.ex > specialPoint.x ? specialPoint.ex - specialPoint.x : 0;
+  const height =
+    specialPoint.ey > specialPoint.y ? specialPoint.ey - specialPoint.y : 0;
+  return {
+    top: specialPoint.y + "px",
+    left: specialPoint.x + "px",
+    width: width + "px",
+    height: height + "px",
+    position: "absolute",
+    border: "1px solid red",
+    borderRadius: "50%",
+    zIndex: 9,
+  };
+});
+
+function specialMouseStart(e: MouseEvent, item: SliceImage) {
+  curImageTarget = e.target.parentElement.childNodes[0];
+  curSliceImagesWithTrackItem = item;
+  specialPoint.x = e.offsetX;
+  specialPoint.y = e.offsetY;
+}
+function specialMouseMove({ left, top }) {
+  specialPoint.ex = left + specialPoint.x;
+  specialPoint.ey = top + specialPoint.y;
+}
+function specialMouseStop(e: MouseEvent) {
+  if (
+    store.currentSpecialTagType === "LINE" &&
+    specialPoint.ex <= specialPoint.x
+  ) {
+    return;
+  }
+  if (
+    store.currentSpecialTagType === "CIRCLE" &&
+    (specialPoint.ex <= specialPoint.x || specialPoint.ey <= specialPoint.y)
+  ) {
+    return;
+  }
+
+  const track: SpecialTag = {
+    tagName: "",
+    tagType: store.currentSpecialTagType,
+    offsetIndex: curSliceImagesWithTrackItem.indexInSliceUrls,
+    offsetX:
+      specialPoint.x * (curImageTarget.naturalWidth / curImageTarget.width) +
+      curSliceImagesWithTrackItem.dx,
+    offsetY:
+      specialPoint.y * (curImageTarget.naturalHeight / curImageTarget.height) +
+      curSliceImagesWithTrackItem.dy,
+    positionX: -1,
+    positionY: -1,
+  };
+  track.positionX =
+    (specialPoint.x - curSliceImagesWithTrackItem.dx) / maxImageWidth;
+  track.positionY =
+    (specialPoint.y -
+      curSliceImagesWithTrackItem.dy +
+      curSliceImagesWithTrackItem.accumTopHeight) /
+    theFinalHeight;
+
+  if (store.currentSpecialTagType === "LINE") {
+    track.tagName = JSON.stringify({
+      len:
+        (specialPoint.ex - specialPoint.x) *
+        (curImageTarget.naturalWidth / curImageTarget.width),
+    });
+  }
+  if (store.currentSpecialTagType === "CIRCLE") {
+    track.tagName = JSON.stringify({
+      width:
+        (specialPoint.ex - specialPoint.x) *
+        (curImageTarget.naturalWidth / curImageTarget.width),
+      height:
+        (specialPoint.ey - specialPoint.y) *
+        (curImageTarget.naturalHeight / curImageTarget.height),
+    });
+  }
+
+  store.currentTaskEnsured.markResult.specialTagList.push(track);
+  curSliceImagesWithTrackItem.tagList.push(track);
+  specialPoint = { x: 0, y: 0, ex: 0, ey: 0 };
+}
+//#endregion
+
 //#region : 显示大图,供查看和翻转
 const showBigImage = (event: MouseEvent) => {
   event.preventDefault();
@@ -529,3 +675,14 @@ function scrollToFirstScore() {
 }
 //#endregion
 </script>
+
+<style scoped>
+.image-canvas {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  z-index: 9;
+}
+</style>

+ 25 - 12
src/features/check/MarkBody.vue

@@ -7,9 +7,17 @@
   <div class="cursor">
     <div class="cursor-border">
       <span v-if="store.currentSpecialTagType === 'TEXT'" class="text">文</span>
-      <!-- <span v-else-if="store.currentSpecialTagType === 'RIGHT'" class="text">
-        <CheckOutlined
-      /></span> -->
+      <span
+        v-else-if="
+          store.currentSpecialTagType === 'LINE' ||
+          store.currentSpecialTagType === 'CIRCLE'
+        "
+        class="point"
+      >
+      </span>
+      <span v-else-if="store.currentSpecialTagType === 'RIGHT'" class="text">
+        <CheckOutlined />
+      </span>
       <span v-else-if="store.currentSpecialTag" class="text">
         {{ store.currentSpecialTag }}
       </span>
@@ -27,7 +35,7 @@ import { store } from "@/store/store";
 import { SliceImage, SpecialTag, Track } from "@/types";
 import CustomCursor from "custom-cursor.js";
 import CommonMarkBody from "./CommonMarkBody.vue";
-// import { CheckOutlined } from "@ant-design/icons-vue";
+import { CheckOutlined } from "@ant-design/icons-vue";
 
 // import { message } from "ant-design-vue";
 // 开启本组件,测试后台在整卷的还原效果
@@ -51,8 +59,12 @@ const makeScoreTrack = (
     score: store.currentScore,
     unanswered: Object.is(store.currentScore, -0),
     offsetIndex: item.indexInSliceUrls,
-    offsetX: event.offsetX * (target.naturalWidth / target.width) + item.dx,
-    offsetY: event.offsetY * (target.naturalHeight / target.height) + item.dy,
+    offsetX: Math.round(
+      event.offsetX * (target.naturalWidth / target.width) + item.dx
+    ),
+    offsetY: Math.round(
+      event.offsetY * (target.naturalHeight / target.height) + item.dy
+    ),
     positionX: -1,
     positionY: -1,
     number: -1,
@@ -150,8 +162,12 @@ const makeSpecialTagTrack = (
     tagName: store.currentSpecialTag,
     tagType: store.currentSpecialTagType,
     offsetIndex: item.indexInSliceUrls,
-    offsetX: event.offsetX * (target.naturalWidth / target.width) + item.dx,
-    offsetY: event.offsetY * (target.naturalHeight / target.height) + item.dy,
+    offsetX: Math.round(
+      event.offsetX * (target.naturalWidth / target.width) + item.dx
+    ),
+    offsetY: Math.round(
+      event.offsetY * (target.naturalHeight / target.height) + item.dy
+    ),
     positionX: -1,
     positionY: -1,
     groupNumber: store.currentQuestion.groupNumber,
@@ -183,10 +199,7 @@ const makeTrack = (
   maxSliceWidth: number,
   theFinalHeight: number
 ) => {
-  if (
-    store.setting.uiSetting["specialTag.modal"] &&
-    store.currentSpecialTagType
-  ) {
+  if (store.currentSpecialTagType) {
     makeSpecialTagTrack(event, item, maxSliceWidth, theFinalHeight);
     if (store.currentSpecialTagType === "TEXT") {
       store.currentSpecialTag = undefined;

+ 1 - 1
src/features/mark/CommonMarkBody.vue

@@ -35,7 +35,7 @@
               :sliceImageHeight="item.sliceImageHeight"
               :dx="item.dx"
               :dy="item.dy"
-              @deleteSpecialtag="(tag) => deleteSpecialtag(item, tag)"
+              @delete-specialtag="(tag) => deleteSpecialtag(item, tag)"
               @click-specialtag="(event) => clickSpecialtag(event, item)"
             />
             <div

+ 13 - 4
src/features/mark/MarkBody.vue

@@ -59,8 +59,13 @@ const makeScoreTrack = (
     score: store.currentScore,
     unanswered: Object.is(store.currentScore, -0),
     offsetIndex: item.indexInSliceUrls,
-    offsetX: event.offsetX * (target.naturalWidth / target.width) + item.dx,
-    offsetY: event.offsetY * (target.naturalHeight / target.height) + item.dy,
+    // 新增轨迹时会校验轨迹是否距离边缘过近,使用round产生的误差可以忽略,不会发生超出边界的问题
+    offsetX: Math.round(
+      event.offsetX * (target.naturalWidth / target.width) + item.dx
+    ),
+    offsetY: Math.round(
+      event.offsetY * (target.naturalHeight / target.height) + item.dy
+    ),
     positionX: -1,
     positionY: -1,
     number: -1,
@@ -157,8 +162,12 @@ const makeSpecialTagTrack = (
     tagName: store.currentSpecialTag,
     tagType: store.currentSpecialTagType,
     offsetIndex: item.indexInSliceUrls,
-    offsetX: event.offsetX * (target.naturalWidth / target.width) + item.dx,
-    offsetY: event.offsetY * (target.naturalHeight / target.height) + item.dy,
+    offsetX: Math.round(
+      event.offsetX * (target.naturalWidth / target.width) + item.dx
+    ),
+    offsetY: Math.round(
+      event.offsetY * (target.naturalHeight / target.height) + item.dy
+    ),
     positionX: -1,
     positionY: -1,
   };

+ 2 - 2
src/features/mark/MarkDrawTrack.vue

@@ -215,8 +215,8 @@ watch(
           item.subNumber == topTrack.subNumber
       );
       document
-        .querySelector(
-          `#a-${topTrack.mainNumber}-${topTrack.subNumber}-${
+        .getElementById(
+          `a-${topTrack.mainNumber}-${topTrack.subNumber}-${
             find?.offsetY || topTrack.offsetY
           }-${find?.offsetX || topTrack.offsetX}`
         )